SlideShare uma empresa Scribd logo
1 de 92
1 of 92
Hidden Gems of Performance Tuning:
Hierarchical Profiler
and
DML Trigger Optimization
Michael Rosenblum
www.dulcian.com
2 of 92
Who Am I? – “Misha”
Oracle ACE
Co-author of 3 books
 PL/SQL for Dummies
 Expert PL/SQL Practices
 Oracle PL/SQL Performance Tuning Tips & Techniques
Known for:
 SQL and PL/SQL tuning
 Complex functionality
 Code generators
 Repository-based development
3 of 92
Yet another performance
presentation???
NO!
Because:
I will NOT talk about bind variables
 … more than a few [dozen] times 
I will NOT mention extra paid options/products.
 Well…I am a [database] doctor, not a [salesman?] (c) Star Trek
I will NOT be buzzword-compliant
 … so you can be [mostly] CLOUD- and EXADATA-free.
4 of 92
Part 1
PL/SQL Profiling
5 of 92
Tuning (CFO Level)
Means:
Ensuring that available resources are used in the most efficient
way:
 No wasted resources
 No under-utilized resources
 Impact:
Makes CFO happy when they look at hardware costs
6 of 92
Tuning (Practical Level)
Means:
MAKING END-USERS HAPPY!
7 of 92
Reality Check
End-users
DON’T CARE ABOUT:
 CPU utilization/disk workload/etc.
 Being buzzword-compliant by using the coolest technology stack
DO CARE ABOUT:
 Being able to run their business
 … i.e. monthly report should not take two months to prepare!
 Time wasted looking at an hourglass on the screen
 … although the notion of “wasted time” can be managed by using various
psychological tricks (managing expectations!).
8 of 92
So?
It’s all about end-user requests…
3. Application
Server
2. Send data from
Client to app server
5. Database
6. Return Data from
database to app server
1. Client
4. Send data from
app server to database
7. Data in
Application Server
8. Return data from
app server to client
9. Data in
client
… and time is lost here
9 of 92
Let’s assume….
You’ve proven that IT IS a database problem
 ... and not network traffic/slow client/etc.
 … and not the number of round trips from the application server!
You can modify database-related code
 Best case: You know how to use a “thick database approach”
 … i.e. you have high level PL/SQL APIs (that call various SQL queries)
 …and these APIs are called by everybody else (UI/reports/BI/etc.)
 Worst case: If needed, you can add diagnostic PL/SQL calls around
SQL.
10 of 92
A Perfect World
Database
API response
API call
PROCEDURE p_DoSomething IS
BEGIN
p_doSomethingElse1;
sql_1;
p_doSomethingElse2;
sql_2;
…
END;
11 of 92
Less Than Perfect World
Database
SQL
or
PL/SQL
Application Server
void doSomething
{
…
doSomethingElse;
…
}
12 of 92
THE Problem
Database is spending too much time doing something:
Perfect Case [one SQL statement that does not contain any
user-defined functions]
 Many monitoring mechanisms
 Many ways to adjust
 Lots of coverage
Real case [combination of SQL and PL/SQL]
 Hierarchical in its nature  something is calling something that is
calling something else
 Cannot be represented as a sequence of simple cases!
13 of 92
The Hero
PL/SQL Hierarchical Profiler
14 of 92
What can it do for you?
PL/SQL Hierarchical Profiler:
Gathers hierarchical statistics of all calls (both SQL and
PL/SQL) for the duration of the monitoring
 … into a portable trace file
Has powerful aggregation utilities
 … both within the database and using a command-line interface
Available since Oracle 11.1 [replaced PL/SQL Profiler]
 … and constantly improved (significantly changed in 18c!)
15 of 92
Introductory Case
Background:
You have multiple PL/SQL program units calling each other that
have SQL statements within them.
Problem:
You need to know where time is wasted and where it would be
best to spend time on tuning.
16 of 92
Intro (1)
SQL> CREATE DIRECTORY IO AS 'C:IO';
SQL> exec dbms_hprof.start_profiling
(location=>'IO',filename=>'HProf.txt');
SQL> DECLARE
2 PROCEDURE p_doSomething (pi_empno NUMBER) IS
3 BEGIN
4 dbms_lock.sleep(0.1);
5 END;
6 PROCEDURE p_main IS
7 BEGIN
8 dbms_lock.sleep(0.5);
9 FOR c IN (SELECT * FROM emp) LOOP
10 p_doSomething(c.empno);
11 END LOOP;
12 END;
13 BEGIN
14 p_main();
15 END;
16 /
SQL> exec dbms_hprof.stop_profiling;
Destination folder:
WRITE is enough
Spend time
17 of 92
Intro (2)
Raw file (C:IOHProf.txt) is not very readable…
P#V PLSHPROF Internal Version 1.0
P#! PL/SQL Timer Started
P#C PLSQL."".""."__plsql_vm"
P#X 8
P#C PLSQL."".""."__anonymous_block"
P#X 6
P#C PLSQL."".""."__anonymous_block.P_MAIN"#980980e97e42f8ec #6
P#X 63
P#C PLSQL."SYS"."DBMS_LOCK"::9."__pkg_init"
P#X 7
P#R
P#X 119
P#C PLSQL."SYS"."DBMS_LOCK"::11."SLEEP"#e17d780a3c3eae3d #197
P#X 500373
P#R
P#X 586
P#C SQL."".""."__sql_fetch_line9" #9."4ay6mhcbhvbf2"
P#! SELECT * FROM SCOTT.EMP
P#X 3791
P#R
P#X 17
<<… and so on …>>
Call
Elapsed time
between events
Return
from
sub-program
18 of 92
Intro (3)
… but you can and make it readable via the command-line utility:
C:Utl_FileIO>plshprof -output hprof_intro HProf.txt
PLSHPROF: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0
- 64bit Production
[8 symbols processed]
[Report written to 'hprof_intro.html']
<Show files>
19 of 92
Intro Findings
The results are:
All of the time is spent in DBMS_LOCK.SLEEP
 …There are no descendants!
When we drill down, the SLEEP procedure was called from
multiple parent modules!
 This is important because, in one case, time spent is 0.1 per call and in
the other is 0.5 per call.
Oracle 12.2+  SQL ID and first 50 characters of SQL text
 Very nice, especially in the case of Dynamic SQL
Many sorting/reporting options!
20 of 92
Intro (4)
… and also you can analyze the trace file via PL/SQL APIs
 Pro: easier to link with SQL statistics
 Contra: need extra READ privilege on the directory + need to create tables
beforehand [11g,12c – script only / 18c,19с – API or script]
DECLARE
runid NUMBER;
BEGIN
runid := DBMS_HPROF.analyze('IO','HProf.txt');
DBMS_OUTPUT.PUT_LINE('runid = ' || runid);
END;
/
DBMSHP_RUNS
Run_ID PK
…
DBMSHP_Parent_Child_Info
Run_ID PK
ParentSymID FK
ChildSymID FK
…
DBMSHP_Function_Info
SymbolID PK
Run_ID FK
Module
Type
Function
…
21 of 92
Intro (5)
… btw, ANALYZE has some nice options:
 Trace only specific entries
runid := DBMS_HPROF.analyze('IO','HProf.txt',
trace=> '"SCOTT"."F_CHANGE_TX"');
 Trace up to N occurrences
runid := DBMS_HPROF.analyze('IO','HProf.txt',
collect => 20,
trace=> '"SCOTT"."F_CHANGE_TX"');
 Trace starting from N-th occurrence
runid := DBMS_HPROF.analyze('IO','HProf.txt',
skip =>1,
trace=> '"SCOTT"."F_CHANGE_TX"');
22 of 92
18c and Up – no RAW Files (1)
Raw data can be generated into tables directly:
DBMS_HPROF.Create_Tables – new API to create all tables
 script dbmshptab.sql still exists, but considered deprecated
 API has FORCE_IT parameter  if TRUE – drop/recreate tables
Pro:
Only limited privileges are needed to run performance analysis
directly in PROD (no file access at all!)
Contra:
Harder to move off-site for a third-party review
Data volume could get out of hands
23 of 92
18c and Up – no RAW Files (2)
DECLARE
trace_id number;
runid number;
PROCEDURE p_doSomething (pi_empno NUMBER) IS
BEGIN
dbms_lock.sleep(0.1);
END;
PROCEDURE p_main IS
BEGIN
dbms_lock.sleep(0.5);
FOR c IN (SELECT * FROM scott.emp) LOOP
p_doSomething(c.empno);
END LOOP;
END;
BEGIN
trace_id := dbms_hprof.start_profiling ;
p_main();
dbms_hprof.stop_profiling;
runid:=dbms_hprof.analyze(trace_id);
dbms_output.put_line('RunId:'||runid);
END;
Runtime ID
No files!
Persistent ID
24 of 92
True Story #1:
Typical Hierarchical Profiler Use
25 of 92
Typical Situation
Help-desk client’s performance complaints:
Developer checked 10046 trace and couldn’t find anything
suspicious
I noticed that the core query contains a user-defined PL/SQL
function.
Action:
Wrap suspicious call in HProf start/stop in TEST instance (with
the same volume of data)
26 of 92
Suspect
SQL> exec dbms_hprof.start_profiling ('IO', 'HProf_Case1.txt');
SQL> declare
2 v_tx varchar2(32767);
3 begin
4 select listagg(owner_tx,',') within group (order by 1)
5 into v_tx
6 from (
7 select distinct scott.f_change_tx(owner) owner_tx
8 from scott.test_tab
9 );
10 end;
11 /
SQL> exec dbms_hprof.stop_profiling;
1. Only 26 owners!
2. Function is doing
basic formatting
27 of 92
Profile
50k calls?!
Here is my time!
<Show files>
28 of 92
Findings
Problem:
 Time is wasted on very cheap function which is fired lots and lots
of times
 … because the original developer “guessed” at the query behavior
 … i.e. he knew function was doing basic formatting, so the output
would also be distinct
 … but forgot to tell that to the CBO  GIGO!
Solution:
 Rewrite query in a way that helps the CBO
 … and remind all developers:
 The number of function calls in SQL will surprise you if you don’t measure
them.
29 of 92
Fix
SQL> exec dbms_hprof.start_profiling ('IO', 'HProf_Case1_fix.txt');
SQL> declare
2 v_tx varchar2(32767);
3 begin
4 select listagg(owner_tx,',') within group (order by 1)
5 into v_tx
6 from (
7 select scott.f_change_tx(owner) owner_tx
8 from (select distinct owner
9 from scott.test_tab)
10 );
11 end;
12 /
SQL> exec dbms_hprof.stop_profiling
Filter first!
<Show files>
30 of 92
Updated Profile
28 times faster!
26 calls
<Show files>
31 of 92
Extra Test:
SQL in Java and SQL*Plus
32 of 92
Running directly from Java?
Good news:
It works!
You can run multiple statements between START and STOP
Bad news:
No SQL IDs if they run directly (at least we couldn’t get it) 
confused statistics 
 Environment: JDeveloper 11g
33 of 92
Java Sample
String sql =
"begin dbms_hprof.start_profiling (location=>'IO',filename=>'Case1a.txt'); end;";
CallableStatement stmt = conn.prepareCall(sql);
stmt.execute();
PreparedStatement stmt2 =
conn.prepareStatement("select listagg(owner_tx,',') within group (order by 1) result n" +
"from (select distinct scott.f_change_tx(owner) owner_txn" +
" from scott.test_tab) A ");
stmt2.execute();
stmt2 = conn.prepareStatement("select listagg(owner_tx,',') within group (order by 1) n" +
"from (select distinct scott.f_change_tx(owner) owner_txn" +
" from scott.test_tab) B ");
stmt2.execute();
sql = "begin dbms_hprof.stop_profiling; end;";
stmt = conn.prepareCall(sql);
stmt.execute();
Difference!
<Show files>
34 of 92
Impact - Java
100k Calls
No SQL IDs
<Show files>
35 of 92
Running directly from SQL*Plus?
Bad news: the same problem with multiple statements:
SQL> exec dbms_hprof.start_profiling
2 (location=>'IO',filename=>'Case1b_SQLPlus.txt');
SQL> select listagg(owner_tx,',') within group (order by 1) result
2 from (select distinct scott.f_change_tx(owner) owner_tx
3 from scott.test_tab a);
...
SQL> select listagg(owner_tx,',') within group (order by 1)
2 from (select distinct scott.f_change_tx(owner) owner_tx
3 from scott.test_tab b);
...
SQL> exec dbms_hprof.stop_profiling;
36 of 92
Impact – SQL*Plus
100k Calls
<Show files>
No SQL IDs
(even in 19c)
37 of 92
True Story #2:
Unexpected Usage
38 of 92
Background
Third-party module code is slow
Functionality: Take some tables and columns /return formatted
CLOB
The code is wrapped
Original developers don’t want to accept the blame.
Action:
Gather as many statistics about the module as you can
Wrap suspicious call in HProf start/stop
39 of 92
Statistics (1)
SQL> exec runstats_pkg.rs_start;
SQL> DECLARE
2 v_CL CLOB;
3 BEGIN
4 v_cl :=wrapped_pkg.f_getdata_cl('ename','emp');
5 dbms_output.put_line('length:'||LENGTH(v_cl));
6 END;
7 /
length:84
SQL> exec runstats_pkg.rs_middle;
SQL> DECLARE
2 v_CL CLOB;
3 BEGIN
4 v_cl :=wrapped_pkg.f_getdata_cl('object_name','test_tab');
5 dbms_output.put_line('length:'||LENGTH(v_cl));
6 END;
7 /
length:1247887
50000 rows
Wrapped module
14 rows
40 of 92
Statistics (2)
SQL> exec runstats_pkg.rs_stop;
Run1 ran in 0 cpu hsecs
Run2 ran in 3195 cpu hsecs
run 1 ran in 0% of the time
Name Run1 Run2 Diff
...
STAT...physical reads direct (lob) 13 49,991 49,978
STAT...physical reads direct temporary tablespace 13 49,991 49,978
STAT...lob writes 14 50,000 49,986
STAT...physical writes direct temporary tablespace 14 50,145 50,131
STAT...physical writes direct (lob) 14 50,145 50,131
Direct Temp I/O?!?!
41 of 92
Profile for the Slow Case
Explicit
“create temp”
50k calls
42 of 92
Analysis
Problem #1: Direct IO for all temporary LOB operations
Could happen only if LOB variable is initiated as NOCACHE
via DBMS_LOB.createTemporary
Problem #2: IO operation for every row in conjunction
with fetch for every row
Could happen only if DBMS_LOB.writeAppend is called within
the loop
43 of 92
Unwrapped code (FYI)
FUNCTION f_getData_cl(i_column_tx VARCHAR2, i_table_tx VARCHAR2) RETURN CLOB IS
v_cl CLOB;
v_tx VARCHAR2(32767);
v_cur SYS_REFCURSOR;
BEGIN
dbms_lob.createTemporary(v_cl,false,dbms_lob.call);
OPEN v_cur FOR 'SELECT '||
dbms_assert.simple_sql_name(i_column_tx)||' field_tx'||
' FROM '||dbms_assert.simple_sql_name(i_table_tx);
LOOP
FETCH v_cur into v_tx;
EXIT WHEN v_cur%notfound;
dbms_lob.writeAppend(v_cl,length(v_tx)+1,v_tx||'|');
END LOOP;
CLOSE v_cur;
RETURN v_cl;
END;
Issue #1:
no cache
Issue #2:
no buffer
<Show optimized code if time permits>
44 of 92
Part1: Summary
End users only care that their requests come back quickly
… and not about CPU/Memory/IO utilization
Yes, sometimes it IS the database 
… but 90% of time it isn’t 
PL/SQL Hierarchical profiler lets you see the system from
the end-user angle and find real performance issues
…i.e. request-driven (with drill-down option)
PL/SQL Hierarchical profiler is constantly improving
.. i.e. don’t forget to read “New Features” guide!
45 of 92
Part 2
Trigger Discipline
46 of 92
Handle with care…
Triggers
Given a lot of bad publicity
 …Some Oracle gurus think that they should never have existed!
Getting more complex with each Oracle release
 … Cross-edition triggers, compound triggers, event triggers…
Constantly misused
 … But can be very useful when applied appropriately!
47 of 92
1.DML triggers
48 of 92
Danger Area
Developers have different reasons to use DML triggers
… but very few are valid.
Problems start when triggers are asked to perform complex
tasks
… although, there is nothing wrong with enforcing the format of
a Social Security Number field (for example).
Any solution that requires a DML trigger to touch data
outside of the current row is questionable.
49 of 92
Anti-Pattern
Requirement:
A person can have a number of mailing addresses.
Only one is designated to be “current.”
Common (wrong!) solution:
Column Current_YN is added to ADDRESS table.
Complex trigger-based solutions are needed to avoid
ORA-04091 “Table is mutating”
 … and yes, I know about compound triggers 
50 of 92
No Triggers Here!
Correct Solution:
Add reverse key to PERSON
Person
Person_ID PK
Name_TX
PrimaryAddress_FK FK
Address
Address_ID PK
Person_FK FK
City_TX
….
0..1 0..*
0..* 0..1
>> Person may have address >>
<< One of the addresses is defined as current <<
51 of 92
1.1. Constraints vs. Triggers
52 of 92
Single Condition
Same business logic/different implementation?
-- option 1:
ALTER TABLE emp add CONSTRAINT emp_sal_ck CHECK (sal<=5000);
-- option 2:
CREATE OR REPLACE TRIGGER emp_row_biu
BEFORE INSERT OR UPDATE ON emp FOR EACH ROW
BEGIN
IF :NEW.sal>5000 THEN
raise_application_error(-20001,
'salary cannot exceed 5000');
END IF;
END;
53 of 92
With Constraint…
SQL> ALTER TABLE emp add CONSTRAINT emp_sal_ck CHECK (sal<=5000);
SQL> SET AUTOTRACE TRACEONLY EXPLAIN
SQL> SELECT * FROM emp WHERE sal > 10000;
Execution Plan
----------------------------------------------------------
Plan hash value: 1341312905
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes| Cost (%CPU)| Time
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1| 38| 0 (0)|
|* 1 | FILTER | | | | |
|* 2 | TABLE ACCESS FULL| EMP | 1| 38| 3 (0)| 00:00:01
-------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(NULL IS NOT NULL)
2 - filter("SAL">10000)
Don’t do ANYTHING!
54 of 92
Without Constraint…
SQL> ALTER TABLE emp DISABLE CONSTRAINT emp_sal_ck;
SQL> select * from emp where sal > 10000;
Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932
------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 3 (0)| 00:00:01
|* 1 | TABLE ACCESS FULL| EMP | 1 | 38 | 3 (0)| 00:00:01
------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("SAL">10000) Full table scan!
55 of 92
Single Condition Summary
Check constraints are part of metadata  CBO impact
… as long as they are enabled and validated.
Triggers hide business logic from Oracle, but they give you
more power.
What if you need to check multiple conditions?
56 of 92
Multiple Conditions - Constraints
SQL> ALTER TABLE emp
2 ADD CONSTRAINT emp_comm_ck CHECK (comm<=2000);
SQL> UPDATE emp
2 SET sal=10000,
3 comm=3000
4 WHERE empno=7902;
UPDATE emp SET sal=10000,comm=3000 WHERE empno=7902
*
ERROR at line 1:
ORA-02290: check constraint(SCOTT.EMP_COMM_CK) violated
Second condition
Only one error!
Two violations
57 of 92
Multiple Conditions – Trigger
SQL> CREATE OR REPLACE TRIGGER emp_row_biu
2 BEFORE INSERT OR UPDATE ON emp
3 FOR EACH ROW
4 DECLARE
5 v_error_tx VARCHAR2(32767);
6 BEGIN
7 IF :NEW.sal>5000 THEN
8 v_error_tx:=v_error_tx||CHR(10)||
9 '* salary cannot exceed 5000';
10 END IF;
11 IF :NEW.comm>2000 THEN
12 v_error_tx:=v_error_tx||CHR(10)||
13 '* commissions cannot exceed 2000';
14 END IF;
15 IF v_error_tx IS NOT NULL THEN
16 raise_application_error(-20001,'Errors:'||v_error_tx);
17 END IF;
18 end;
19 /
Aggregator
58 of 92
Multiple Conditions - Constraints
SQL> UPDATE emp
2 SET sal=10000,comm=3000
3 WHERE empno=7902;
UPDATE emp SET sal=10000,comm=3000 WHERE empno=7902
*
ERROR at line 1:
ORA-20001: Errors:
* salary cannot exceed 5000
* commissions cannot exceed 2000
ORA-06512: at "SCOTT.EMP_ROW_BIU", line 15
ORA-04088: error during execution of trigger 'SCOTT.EMP_ROW_BIU'
Both errors!
59 of 92
Multiple Conditions - Summary
Triggers:
Allow multiple errors to be propagated.
Allow human-readable error messages.
Repeated warning:
Implementing cross-row conditions (“Salary Cannot exceed
150% of the average in the department”) as triggers is very
dangerous!
 … just Google “read consistency”
60 of 92
1.2 Default Values
61 of 92
Populating Sequence ID
Available options:
Explicitly pass into INSERT
Before-INSERT trigger
Default=SEQUENCE.NEXTVAL (Oracle 12c+)
62 of 92
Sample Set
CREATE SEQUENCE test_trigger_seq;
CREATE TABLE test_trigger_tab1
(a NUMBER,
b VARCHAR2(1));
CREATE OR REPLACE TRIGGER test_trigger_tab1_bi
BEFORE INSERT ON test_trigger_tab1 FOR EACH ROW DISABLE
BEGIN
IF :NEW.a IS NULL THEN
:NEW.a:=test_trigger_seq.NEXTVAL;
END IF;
END;
Starting disabled
63 of 92
Compare Pre-12c Options
SQL> exec runstats_pkg.rs_start;
SQL> ALTER TRIGGER test_trigger_tab1_bi ENABLE;
SQL> BEGIN
2 FOR i IN 1..10000 LOOP
3 INSERT INTO test_trigger_tab1(b) VALUES ('X');
4 END LOOP;
5 END;
6 /
SQL> exec runstats_pkg.rs_middle;
SQL> ALTER TRIGGER test_trigger_tab1_bi DISABLE;
SQL> BEGIN
2 FOR i IN 1..10000 LOOP
3 INSERT INTO test_trigger_tab1(a,b) VALUES(test_trigger_seq.NEXTVAL,'X')
4 END LOOP;
5 END;
6 /
SQL> exec runstats_pkg.rs_stop;
Run1 ran in 281 cpu hsecs
Run2 ran in 172 cpu hsecs
Name Run1 Run2 Diff
STAT...recursive cpu usage 268 147 -121
STAT...recursive calls 20,641 10,594 -10,047
Trigger overhead
64 of 92
Pre-12c vs. 12c
SQL> exec runstats_pkg.rs_start;
SQL> ALTER TABLE test_trigger_tab1
2 MODIFY a DEFAULT test_trigger_seq.NEXTVAL;
<<< ... 10 000 inserts ... >>>
SQL> exec runstats_pkg.rs_middle;
SQL> ALTER TABLE test_trigger_tab1 MODIFY a DEFAULT NULL;
SQL> BEGIN
2 FOR i IN 1..10000 LOOP
3 INSERT INTO test_trigger_tab1(a,b) VALUES (test_trigger_seq.NEXTVAL,'X');
5 END LOOP;
6 END;
7 /
SQL> exec runstats_pkg.rs_stop;
Run1 ran in 178 cpu hsecs
Run2 ran in 157 cpu hsecs
run 1 ran in 113.38% of the time
Name Run1 Run2 Diff
STAT...recursive cpu usage 164 136 -28
Much closer!
65 of 92
2. INSTEAD-OF Triggers
66 of 92
INSTEAD OF Trigger Issues
DML against views with INSTEAD OF triggers behave
differently in comparison to regular DML
… especially for function-based views.
Developers often misunderstand how these triggers work
… and mishandle logical primary keys.
Proper handling of UPDATEs require deep understanding
of Oracle UNDO mechanisms.
67 of 92
2.1 DMLs Against
Function-Based Views
68 of 92
Test Case (1)
CREATE TYPE test_tab_ot AS OBJECT (owner_tx VARCHAR2(30),
name_tx VARCHAR2(30),
object_id NUMBER,
type_tx VARCHAR2(30));
CREATE TYPE test_tab_nt IS TABLE OF test_tab_ot;
CREATE FUNCTION f_searchTestTab_tt (i_type_tx VARCHAR2) RETURN test_tab_nt IS
v_out_tt test_tab_nt;
begin
SELECT test_tab_ot(owner, object_name, object_id, object_type)
BULK COLLECT INTO v_out_tt
FROM test_tab
WHERE object_type = i_type_tx;
dbms_output.put_line('Inside f_searchTestTab_tt:'||v_out_tt.count);
RETURN v_out_tt;
END;
69 of 92
Test Case (2)
create or replace view v_search_table as
select *
from table(f_searchtesttab_tt('TABLE'));
create or replace trigger v_search_table_iiud
instead of insert or update or delete on v_search_table
begin
if inserting then
dbms_output.put_line('Insert');
elsif updating then
dbms_output.put_line('Update');
elsif deleting then
dbms_output.put_line(‘Delete');
end if;
end;
70 of 92
DML Check
SQL> INSERT INTO v_search_table (object_id, name_tx)
2 VALUES (-1,'A');
Insert
1 row created.
SQL> UPDATE v_search_table SET name_tx = 'Test‘
2 WHERE object_id = 5;
Inside f_searchTestTab_tt:1541
Update
1 row updated.
SQL> DELETE FROM v_search_table WHERE object_id = 5;
Inside f_searchTestTab_tt:1541
Delete
1 row deleted.
Function is not fired!
Process all to update one?
71 of 92
Side-Effect of
Function-Based Views
Real problem:
WHERE clauses on function-based views are extremely
inefficient.
Solution:
Pass conditions as parameters into the function.
72 of 92
Parameterized View (1)
CREATE PACKAGE global_pkg IS
v_object_id NUMBER;
END;
CREATE FUNCTION f_searchTestTab_tt (i_type_tx varchar2) RETURN test_tab_nt is
v_out_tt test_tab_nt;
BEGIN
IF global_pkg.v_object_id IS NULL THEN
SELECT test_tab_ot(owner, object_name, object_id, object_type)
BULK COLLECT INTO v_out_tt
FROM test_tab
WHERE object_type = i_type_tx;
ELSE
SELECT test_tab_ot(owner, object_name, object_id, object_type)
BULK COLLECT INTO v_out_tt
FROM test_tab
WHERE object_id = global_pkg.v_object_id;
END IF;
dbms_output.put_line
('Inside f_searchTestTab_tt:'||v_out_tt.count);
RETURN v_out_tt;
END;
Usage (if needed)
Global parameter
73 of 92
Parameterized View (2)
SQL> BEGIN global_pkg.v_object_id:=5; END;
2 /
SQL> UPDATE v_search_table SET name_tx = 'Test'
2 WHERE object_id = 5;
Inside f_searchTestTab_tt:1
Update
1 row updated.
SQL> DELETE FROM v_search_table WHERE object_id = 5;
Inside f_searchTestTab_tt:1
Delete
1 row deleted.
74 of 92
Parameterized View (3)
SQL> exec runstats_pkg.rs_start;
SQL> BEGIN
2 global_pkg.v_object_id:=NULL;
3 FOR i IN 1..100 LOOP
4 UPDATE v_search_table SET name_tx = 'Test'||i
5 WHERE object_id = 5;
6 END LOOP;
7 END;
8 /
SQL> exec runstats_pkg.rs_middle;
SQL> BEGIN
2 global_pkg.v_object_id:=5;
3 FOR i IN 1..100 LOOP
4 UPDATE v_search_table SET name_tx = 'Test'||i
5 WHERE object_id = 5;
6 END LOOP;
7 END;
8 /
SQL> exec runstats_pkg.rs_stop;
Run1 ran in 181 cpu hsecs
Run2 ran in 28 cpu hsecs
run 1 ran in 646.43% of the time
5x improvement
75 of 92
2.2 Dangers of
Logical Primary Keys
76 of 92
The Real Story
Synthetic primary keys on views
Sometimes required by front-end environments (to uniquely
identify the row in the cache)
Extremely dangerous if blindly used for
INSERT/UPDATE/DELETE
77 of 92
Test Case
CREATE OR REPLACE VIEW v_test_tab
AS
SELECT 'Main|'||object_id pk_tx,
a.*
FROM test_tab_main a
UNION ALL
SELECT 'Other|'||object_id pk_tx,
a.*
FROM test_tab_other a;
78 of 92
Performance Impact
SQL> set autotrace traceonly explain
SQL> UPDATE v_test_tab
2 SET object_name='Test'
3 WHERE pk_tx='Main|1';
1 row updated.
Execution Plan
----------------------------------------------------------
Plan hash value: 3568876726
-------------------------------------------------------------------------
|Id| Operation | Name | Rows | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------
| 0| UPDATE STATEMENT | | 500 | 45500 | 236 (1)|
| 1| UPDATE | V_TEST_TAB | | | |
| 2| VIEW | V_TEST_TAB | 500 | 45500 | 236 (1)|
| 3| UNION-ALL | | | | |
|*4| TABLE ACCESS FULL| TEST_TAB_MAIN | 15 | 330 | 9 (0)|
|*5| TABLE ACCESS FULL| TEST_TAB_OTHER | 485 | 14550 | 227 (1)|
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter('Main|'||TO_CHAR("OBJECT_ID")='Main|1')
5 - filter('Other|'||TO_CHAR("OBJECT_ID")='Main|1')
Full-table scans!
79 of 92
2.3 Handling UPDATEs
80 of 92
Resource Issues
Problem
 INSTEAD-OF UPDATE triggers often reference all columns of the
underlying tables
 … instead of trying to figure out what has been changed.
 UNDO is generated for all columns mentioned in the UPDATE
statement
 … irrelevant whether they were changed or not
 … which causes major I/O overhead
Alternative:
 Use Dynamic SQL to modify only changed columns
 … i.e. trade off CPU utilization for better I/O!
81 of 92
Regular Trigger
create or replace trigger v_test_tab_iu
instead of update on v_test_tab
begin
if :new.object_type='TABLE' then
update test_tab_main
set owner=:new.owner, object_name=:new.object_name,
subobject_name=:new.subobject_name,
object_type=:new.object_type,
created=:new.created, last_ddl_time=:new.last_ddl_time,
timestamp=:new.timestamp, status=:new.status,
temporary=:new.temporary, generated=:new.generated,
secondary=:new.secondary, namespace=:new.namespace,
edition_name=:new.edition_name, sharing=:new.sharing,
editionable=:new.editionable,
oracle_maintained=:new.oracle_maintained
where object_id=:old.object_id;
else
update test_tab_other
set << the same list of columns as above >>
where object_id=:old.object_id;
end if;
end;
82 of 92
Dynamic SQL Trigger (1)
create or replace trigger v_test_tab_dynamic_iu
instead of update on v_test_tab
declare
v_main_rec test_tab_main%rowtype;
v_mainupdate_tx varchar2(32767);
v_other_rec test_tab_other%rowtype;
v_otherupdate_tx varchar2(32767);
begin
if :new.object_type='table' then
-- compare old/new for each attribute
if :old.object_name is null and :new.object_name is not null
or :old.object_name is not null and :new.object_name is null
or :old.object_name!=:new.object_name then
v_main_rec.object_name:=:new.object_name;
v_mainupdate_tx:=v_mainupdate_tx||
case
when v_mainupdate_tx is not null then ','
else null
end||chr(10)||
' object_name=v_rec.object_name';
end if;
...
Store new value
(if changed)
83 of 92
Dynamic SQL Trigger (2)
v_main_rec.object_id:=:old.object_id;
v_mainupdate_tx:=
'declare '||chr(10)||
' v_rec test_tab_main%rowtype:=:1;'||chr(10)||
'begin '||chr(10)||
' update test_tab_main ' ||chr(10)||
' set '||v_mainupdate_tx||chr(10)||
' where object_id=v_rec.object_id;'||chr(10)||
'end;';
execute immediate v_mainupdate_tx using v_main_rec;
else
<< the same logic as above for test_tab_other >>
end if;
end;
84 of 92
Performance Tradeoff
SQL> exec runstats_pkg.rs_start;
<<disable Dynamic trigger, enable regular trigger>>
SQL> begin
2 for i in 1..10000 loop
3 UPDATE v_test_tab SET object_name='Test'||i WHERE object_id = 5;
4 end loop;
5 END;
6 /
SQL> exec runstats_pkg.rs_middle;
<<enable Dynamic trigger, disable regular trigger and rerun the same logic>>
SQL> exec runstats_pkg.rs_stop;
Run1 ran in 390 cpu hsecs
Run2 ran in 496 cpu hsecs
run 1 ran in 78.63% of the time
Name Run1 Run2 Diff
STAT...recursive calls 20,329 30,244 9,915
STAT...execute count 20,102 30,095 9,993
STAT...undo change vector size 2,495,476 938,552 -1,556,924
STAT...redo size 5,820,096 2,772,332 -3,047,764
Run1 latches total versus runs -- difference and pct
Run1 Run2 Diff Pct
136,486 184,679 48,193 73.90%
More CPU time
Much less I/O
85 of 92
3. Compound Triggers
(on Views!)
86 of 92
Extending INSTEAD OF
You can also create a COMPOUND trigger instead of an
INSTEAD OF trigger 
Trigger with common program area
Impact
Pro:
 Common program area – possible to share code and global variables 
simulating statement-level BEFORE event
 Sorry - there is no way to simulate an AFTER event
Con:
 Yet another place to hide business logic
87 of 92
CREATE OR REPLACE PACKAGE counter_pkg IS
v_nr NUMBER:=0;
PROCEDURE p_check;
procedure p_up;
END;
CREATE OR REPLACE PACKAGE BODY counter_pkg IS
PROCEDURE p_check is
BEGIN
dbms_output.put_line('Fired:'||counter_pkg.v_nr);
counter_pkg.v_nr:=0;
END;
procedure p_up is
begin
counter_pkg.v_nr:=counter_pkg.v_nr+1;
end;
END;
create or replace function f_securityCheck_yn return varchar2 is
begin
counter_pkg.p_up;
if sys_context ('USERENV', 'CLIENT_INFO') ='SalMaint' then
return 'Y';
else
return 'N';
end if;
end;
Monitoring Tool
88 of 92
CREATE OR REPLACE TRIGGER v_search_table_IIUD
INSTEAD OF INSERT OR UPDATE OR DELETE ON v_search_table
BEGIN
if f_securityCheck_yn = 'Y' then
IF INSERTING THEN
dbms_output.put_line('Insert');
ELSIF UPDATING THEN
dbms_output.put_line('Update');
ELSIF DELETING THEN
dbms_output.put_line('Delete');
END IF;
end if;
END;
Option A - Regular
89 of 92
create or replace trigger v_search_table_IIUD_comp
for insert or update or delete on v_search_table
COMPOUND TRIGGER
v_check_yn varchar2(1);
instead of each row is
begin
if v_check_yn is null then
v_check_yn:=f_securityCheck_yn;
end if;
if v_check_yn = 'Y' then
IF INSERTING THEN
dbms_output.put_line('Insert');
ELSIF UPDATING THEN
dbms_output.put_line('Update');
ELSIF DELETING THEN
dbms_output.put_line('Delete');
END IF;
end if;
end instead of each row;
end;
Option B - Compound
Common area
Row-level trigger
90 of 92
SQL> alter trigger v_search_table_IIUD_COMP disable;
SQL> alter trigger v_search_table_IIUD enable;
SQL> update v_search_table set name_tx = 'Test';
Inside f_searchTestTab_tt:1571
1571 rows updated.
SQL> exec counter_pkg.p_check;
Fired:1571
SQL> alter trigger v_search_table_IIUD_COMP enable;
SQL> alter trigger v_search_table_IIUD disable;
SQL> update v_search_table set name_tx = 'Test';
Inside f_searchTestTab_tt:1571
1571 rows updated.
SQL> exec counter_pkg.p_check;
Fired:1
SQL> exec dbms_application_info.set_client_info('SalMaint');
SQL> update v_search_table set name_tx = 'Test';
Inside f_searchTestTab_tt:1571
Update
Update
....
1571 rows updated.
SQL> exec counter_pkg.p_check;
Fired:1
Performance Impact
Only one call!
Option A - Decline
Option B - Decline
Option B - Success
91 of 92
Part 2: Summary
Triggers are very powerful (as long as they are applied
correctly).
“Mutating tables” issue usually hides architectural mistakes.
… and compound triggers could solve other problems too!
INSTEAD OF triggers have to be handled carefully.
92 of 92
Contact Information
 Michael Rosenblum – mrosenblum@dulcian.com
 Dulcian, Inc. website - www.dulcian.com
 Blog: wonderingmisha.blogspot.com

Mais conteúdo relacionado

Mais procurados

Oracle Database 12.1.0.2 New Features
Oracle Database 12.1.0.2 New FeaturesOracle Database 12.1.0.2 New Features
Oracle Database 12.1.0.2 New FeaturesAlex Zaballa
 
Database administration commands
Database administration commands Database administration commands
Database administration commands Varsha Ajith
 
Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014
Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014
Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014Alex Zaballa
 
Oracle Data redaction - GUOB - OTN TOUR LA - 2015
Oracle Data redaction - GUOB - OTN TOUR LA - 2015Oracle Data redaction - GUOB - OTN TOUR LA - 2015
Oracle Data redaction - GUOB - OTN TOUR LA - 2015Alex Zaballa
 
Database & Technology 1 _ Tom Kyte _ Efficient PL SQL - Why and How to Use.pdf
Database & Technology 1 _ Tom Kyte _ Efficient PL SQL - Why and How to Use.pdfDatabase & Technology 1 _ Tom Kyte _ Efficient PL SQL - Why and How to Use.pdf
Database & Technology 1 _ Tom Kyte _ Efficient PL SQL - Why and How to Use.pdfInSync2011
 
Defcon_Oracle_The_Making_of_the_2nd_sql_injection_worm
Defcon_Oracle_The_Making_of_the_2nd_sql_injection_wormDefcon_Oracle_The_Making_of_the_2nd_sql_injection_worm
Defcon_Oracle_The_Making_of_the_2nd_sql_injection_wormguest785f78
 
Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf
Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdfDatabase & Technology 1 _ Tom Kyte _ SQL Techniques.pdf
Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdfInSync2011
 
MySQL Stored Procedures: Building High Performance Web Applications
MySQL Stored Procedures: Building High Performance Web ApplicationsMySQL Stored Procedures: Building High Performance Web Applications
MySQL Stored Procedures: Building High Performance Web ApplicationsOSSCube
 
EMCLI Crash Course - DOAG Germany
EMCLI Crash Course - DOAG GermanyEMCLI Crash Course - DOAG Germany
EMCLI Crash Course - DOAG GermanyGokhan Atil
 
Oracle Diagnostics : Locks and Lock Trees
Oracle Diagnostics :  Locks and Lock TreesOracle Diagnostics :  Locks and Lock Trees
Oracle Diagnostics : Locks and Lock TreesHemant K Chitale
 
Powerful Explain in MySQL 5.6
Powerful Explain in MySQL 5.6Powerful Explain in MySQL 5.6
Powerful Explain in MySQL 5.6MYXPLAIN
 
[스프링/Spring교육학원,자바교육,근로자교육,실업자교육추천학원_탑크리에듀]#6.스프링프레임워크 & 마이바티스 (Spring Framew...
[스프링/Spring교육학원,자바교육,근로자교육,실업자교육추천학원_탑크리에듀]#6.스프링프레임워크 & 마이바티스 (Spring Framew...[스프링/Spring교육학원,자바교육,근로자교육,실업자교육추천학원_탑크리에듀]#6.스프링프레임워크 & 마이바티스 (Spring Framew...
[스프링/Spring교육학원,자바교육,근로자교육,실업자교육추천학원_탑크리에듀]#6.스프링프레임워크 & 마이바티스 (Spring Framew...탑크리에듀(구로디지털단지역3번출구 2분거리)
 
Bypass dbms assert
Bypass dbms assertBypass dbms assert
Bypass dbms assertfangjiafu
 
Mysql Explain Explained
Mysql Explain ExplainedMysql Explain Explained
Mysql Explain ExplainedJeremy Coates
 
Introduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]sIntroduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]sSveta Smirnova
 
IEEE Day 2013 Oracle Database 12c: new features for developers
IEEE Day 2013 Oracle Database 12c: new features for developersIEEE Day 2013 Oracle Database 12c: new features for developers
IEEE Day 2013 Oracle Database 12c: new features for developersRamin Orujov
 
Meg bernal insight2014 4219
Meg bernal insight2014 4219Meg bernal insight2014 4219
Meg bernal insight2014 4219Peter Schouboe
 

Mais procurados (20)

Noinject
NoinjectNoinject
Noinject
 
Oracle Database 12.1.0.2 New Features
Oracle Database 12.1.0.2 New FeaturesOracle Database 12.1.0.2 New Features
Oracle Database 12.1.0.2 New Features
 
Oracle ORA Errors
Oracle ORA ErrorsOracle ORA Errors
Oracle ORA Errors
 
Database administration commands
Database administration commands Database administration commands
Database administration commands
 
Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014
Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014
Flex Cluster e Flex ASM - GUOB Tech Day - OTN TOUR LA Brazil 2014
 
Oracle Data redaction - GUOB - OTN TOUR LA - 2015
Oracle Data redaction - GUOB - OTN TOUR LA - 2015Oracle Data redaction - GUOB - OTN TOUR LA - 2015
Oracle Data redaction - GUOB - OTN TOUR LA - 2015
 
Database & Technology 1 _ Tom Kyte _ Efficient PL SQL - Why and How to Use.pdf
Database & Technology 1 _ Tom Kyte _ Efficient PL SQL - Why and How to Use.pdfDatabase & Technology 1 _ Tom Kyte _ Efficient PL SQL - Why and How to Use.pdf
Database & Technology 1 _ Tom Kyte _ Efficient PL SQL - Why and How to Use.pdf
 
Defcon_Oracle_The_Making_of_the_2nd_sql_injection_worm
Defcon_Oracle_The_Making_of_the_2nd_sql_injection_wormDefcon_Oracle_The_Making_of_the_2nd_sql_injection_worm
Defcon_Oracle_The_Making_of_the_2nd_sql_injection_worm
 
Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf
Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdfDatabase & Technology 1 _ Tom Kyte _ SQL Techniques.pdf
Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf
 
MySQL Stored Procedures: Building High Performance Web Applications
MySQL Stored Procedures: Building High Performance Web ApplicationsMySQL Stored Procedures: Building High Performance Web Applications
MySQL Stored Procedures: Building High Performance Web Applications
 
EMCLI Crash Course - DOAG Germany
EMCLI Crash Course - DOAG GermanyEMCLI Crash Course - DOAG Germany
EMCLI Crash Course - DOAG Germany
 
Oracle Diagnostics : Locks and Lock Trees
Oracle Diagnostics :  Locks and Lock TreesOracle Diagnostics :  Locks and Lock Trees
Oracle Diagnostics : Locks and Lock Trees
 
Triggers and Stored Procedures
Triggers and Stored ProceduresTriggers and Stored Procedures
Triggers and Stored Procedures
 
Powerful Explain in MySQL 5.6
Powerful Explain in MySQL 5.6Powerful Explain in MySQL 5.6
Powerful Explain in MySQL 5.6
 
[스프링/Spring교육학원,자바교육,근로자교육,실업자교육추천학원_탑크리에듀]#6.스프링프레임워크 & 마이바티스 (Spring Framew...
[스프링/Spring교육학원,자바교육,근로자교육,실업자교육추천학원_탑크리에듀]#6.스프링프레임워크 & 마이바티스 (Spring Framew...[스프링/Spring교육학원,자바교육,근로자교육,실업자교육추천학원_탑크리에듀]#6.스프링프레임워크 & 마이바티스 (Spring Framew...
[스프링/Spring교육학원,자바교육,근로자교육,실업자교육추천학원_탑크리에듀]#6.스프링프레임워크 & 마이바티스 (Spring Framew...
 
Bypass dbms assert
Bypass dbms assertBypass dbms assert
Bypass dbms assert
 
Mysql Explain Explained
Mysql Explain ExplainedMysql Explain Explained
Mysql Explain Explained
 
Introduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]sIntroduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]s
 
IEEE Day 2013 Oracle Database 12c: new features for developers
IEEE Day 2013 Oracle Database 12c: new features for developersIEEE Day 2013 Oracle Database 12c: new features for developers
IEEE Day 2013 Oracle Database 12c: new features for developers
 
Meg bernal insight2014 4219
Meg bernal insight2014 4219Meg bernal insight2014 4219
Meg bernal insight2014 4219
 

Semelhante a Hidden Gems of Performance Tuning: Hierarchical Profiler and DML Trigger Optimization

Server-Side Development for the Cloud
Server-Side Developmentfor the CloudServer-Side Developmentfor the Cloud
Server-Side Development for the CloudMichael Rosenblum
 
Watch Re-runs on your SQL Server with RML Utilities
Watch Re-runs on your SQL Server with RML UtilitiesWatch Re-runs on your SQL Server with RML Utilities
Watch Re-runs on your SQL Server with RML Utilitiesdpcobb
 
BP206 - Let's Give Your LotusScript a Tune-Up
BP206 - Let's Give Your LotusScript a Tune-Up BP206 - Let's Give Your LotusScript a Tune-Up
BP206 - Let's Give Your LotusScript a Tune-Up Craig Schumann
 
Sydney Oracle Meetup - execution plans
Sydney Oracle Meetup - execution plansSydney Oracle Meetup - execution plans
Sydney Oracle Meetup - execution planspaulguerin
 
Oracle Wait Events That Everyone Should Know.ppt
Oracle Wait Events That Everyone Should Know.pptOracle Wait Events That Everyone Should Know.ppt
Oracle Wait Events That Everyone Should Know.pptTricantinoLopezPerez
 
Lotusphere 2007 AD505 DevBlast 30 LotusScript Tips
Lotusphere 2007 AD505 DevBlast 30 LotusScript TipsLotusphere 2007 AD505 DevBlast 30 LotusScript Tips
Lotusphere 2007 AD505 DevBlast 30 LotusScript TipsBill Buchan
 
Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!mold
 
監査ログをもっと身近に!〜統合監査のすすめ〜
監査ログをもっと身近に!〜統合監査のすすめ〜監査ログをもっと身近に!〜統合監査のすすめ〜
監査ログをもっと身近に!〜統合監査のすすめ〜Michitoshi Yoshida
 
Php classes in mumbai
Php classes in mumbaiPhp classes in mumbai
Php classes in mumbaiaadi Surve
 
Best Practices For Drupal Developers By Mir Nazim @ Drupal Camp India 2008
Best Practices For Drupal Developers By Mir Nazim @ Drupal Camp India 2008Best Practices For Drupal Developers By Mir Nazim @ Drupal Camp India 2008
Best Practices For Drupal Developers By Mir Nazim @ Drupal Camp India 2008Mir Nazim
 
Practicas oracle10g
Practicas oracle10gPracticas oracle10g
Practicas oracle10grehoscript
 
Oracle Database 12c - The Best Oracle Database 12c Tuning Features for Develo...
Oracle Database 12c - The Best Oracle Database 12c Tuning Features for Develo...Oracle Database 12c - The Best Oracle Database 12c Tuning Features for Develo...
Oracle Database 12c - The Best Oracle Database 12c Tuning Features for Develo...Alex Zaballa
 
Let your DBAs get some REST(api)
Let your DBAs get some REST(api)Let your DBAs get some REST(api)
Let your DBAs get some REST(api)Ludovico Caldara
 
Microsoft SQL Server Query Tuning
Microsoft SQL Server Query TuningMicrosoft SQL Server Query Tuning
Microsoft SQL Server Query TuningMark Ginnebaugh
 
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...Alex Zaballa
 

Semelhante a Hidden Gems of Performance Tuning: Hierarchical Profiler and DML Trigger Optimization (20)

Server-Side Development for the Cloud
Server-Side Developmentfor the CloudServer-Side Developmentfor the Cloud
Server-Side Development for the Cloud
 
Watch Re-runs on your SQL Server with RML Utilities
Watch Re-runs on your SQL Server with RML UtilitiesWatch Re-runs on your SQL Server with RML Utilities
Watch Re-runs on your SQL Server with RML Utilities
 
Ad505 dev blast
Ad505 dev blastAd505 dev blast
Ad505 dev blast
 
BP206 - Let's Give Your LotusScript a Tune-Up
BP206 - Let's Give Your LotusScript a Tune-Up BP206 - Let's Give Your LotusScript a Tune-Up
BP206 - Let's Give Your LotusScript a Tune-Up
 
Sydney Oracle Meetup - execution plans
Sydney Oracle Meetup - execution plansSydney Oracle Meetup - execution plans
Sydney Oracle Meetup - execution plans
 
Oracle Wait Events That Everyone Should Know.ppt
Oracle Wait Events That Everyone Should Know.pptOracle Wait Events That Everyone Should Know.ppt
Oracle Wait Events That Everyone Should Know.ppt
 
Lotusphere 2007 AD505 DevBlast 30 LotusScript Tips
Lotusphere 2007 AD505 DevBlast 30 LotusScript TipsLotusphere 2007 AD505 DevBlast 30 LotusScript Tips
Lotusphere 2007 AD505 DevBlast 30 LotusScript Tips
 
Sherlock holmes for dba’s
Sherlock holmes for dba’sSherlock holmes for dba’s
Sherlock holmes for dba’s
 
Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!
 
監査ログをもっと身近に!〜統合監査のすすめ〜
監査ログをもっと身近に!〜統合監査のすすめ〜監査ログをもっと身近に!〜統合監査のすすめ〜
監査ログをもっと身近に!〜統合監査のすすめ〜
 
Oracle SQL Tuning
Oracle SQL TuningOracle SQL Tuning
Oracle SQL Tuning
 
Php classes in mumbai
Php classes in mumbaiPhp classes in mumbai
Php classes in mumbai
 
Best Practices For Drupal Developers By Mir Nazim @ Drupal Camp India 2008
Best Practices For Drupal Developers By Mir Nazim @ Drupal Camp India 2008Best Practices For Drupal Developers By Mir Nazim @ Drupal Camp India 2008
Best Practices For Drupal Developers By Mir Nazim @ Drupal Camp India 2008
 
Brad Wood - CommandBox CLI
Brad Wood - CommandBox CLI Brad Wood - CommandBox CLI
Brad Wood - CommandBox CLI
 
Practicas oracle10g
Practicas oracle10gPracticas oracle10g
Practicas oracle10g
 
pm1
pm1pm1
pm1
 
Oracle Database 12c - The Best Oracle Database 12c Tuning Features for Develo...
Oracle Database 12c - The Best Oracle Database 12c Tuning Features for Develo...Oracle Database 12c - The Best Oracle Database 12c Tuning Features for Develo...
Oracle Database 12c - The Best Oracle Database 12c Tuning Features for Develo...
 
Let your DBAs get some REST(api)
Let your DBAs get some REST(api)Let your DBAs get some REST(api)
Let your DBAs get some REST(api)
 
Microsoft SQL Server Query Tuning
Microsoft SQL Server Query TuningMicrosoft SQL Server Query Tuning
Microsoft SQL Server Query Tuning
 
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...
 

Último

Decoding Movie Sentiments: Analyzing Reviews with Data Analysis model
Decoding Movie Sentiments: Analyzing Reviews with Data Analysis modelDecoding Movie Sentiments: Analyzing Reviews with Data Analysis model
Decoding Movie Sentiments: Analyzing Reviews with Data Analysis modelBoston Institute of Analytics
 
Data Factory in Microsoft Fabric (MsBIP #82)
Data Factory in Microsoft Fabric (MsBIP #82)Data Factory in Microsoft Fabric (MsBIP #82)
Data Factory in Microsoft Fabric (MsBIP #82)Cathrine Wilhelmsen
 
NO1 Certified Black Magic Specialist Expert Amil baba in Lahore Islamabad Raw...
NO1 Certified Black Magic Specialist Expert Amil baba in Lahore Islamabad Raw...NO1 Certified Black Magic Specialist Expert Amil baba in Lahore Islamabad Raw...
NO1 Certified Black Magic Specialist Expert Amil baba in Lahore Islamabad Raw...Amil Baba Dawood bangali
 
SMOTE and K-Fold Cross Validation-Presentation.pptx
SMOTE and K-Fold Cross Validation-Presentation.pptxSMOTE and K-Fold Cross Validation-Presentation.pptx
SMOTE and K-Fold Cross Validation-Presentation.pptxHaritikaChhatwal1
 
The Power of Data-Driven Storytelling_ Unveiling the Layers of Insight.pptx
The Power of Data-Driven Storytelling_ Unveiling the Layers of Insight.pptxThe Power of Data-Driven Storytelling_ Unveiling the Layers of Insight.pptx
The Power of Data-Driven Storytelling_ Unveiling the Layers of Insight.pptxTasha Penwell
 
IBEF report on the Insurance market in India
IBEF report on the Insurance market in IndiaIBEF report on the Insurance market in India
IBEF report on the Insurance market in IndiaManalVerma4
 
Student profile product demonstration on grades, ability, well-being and mind...
Student profile product demonstration on grades, ability, well-being and mind...Student profile product demonstration on grades, ability, well-being and mind...
Student profile product demonstration on grades, ability, well-being and mind...Seán Kennedy
 
Minimizing AI Hallucinations/Confabulations and the Path towards AGI with Exa...
Minimizing AI Hallucinations/Confabulations and the Path towards AGI with Exa...Minimizing AI Hallucinations/Confabulations and the Path towards AGI with Exa...
Minimizing AI Hallucinations/Confabulations and the Path towards AGI with Exa...Thomas Poetter
 
Real-Time AI Streaming - AI Max Princeton
Real-Time AI  Streaming - AI Max PrincetonReal-Time AI  Streaming - AI Max Princeton
Real-Time AI Streaming - AI Max PrincetonTimothy Spann
 
Decoding Patterns: Customer Churn Prediction Data Analysis Project
Decoding Patterns: Customer Churn Prediction Data Analysis ProjectDecoding Patterns: Customer Churn Prediction Data Analysis Project
Decoding Patterns: Customer Churn Prediction Data Analysis ProjectBoston Institute of Analytics
 
Data Analysis Project : Targeting the Right Customers, Presentation on Bank M...
Data Analysis Project : Targeting the Right Customers, Presentation on Bank M...Data Analysis Project : Targeting the Right Customers, Presentation on Bank M...
Data Analysis Project : Targeting the Right Customers, Presentation on Bank M...Boston Institute of Analytics
 
Semantic Shed - Squashing and Squeezing.pptx
Semantic Shed - Squashing and Squeezing.pptxSemantic Shed - Squashing and Squeezing.pptx
Semantic Shed - Squashing and Squeezing.pptxMike Bennett
 
Principles and Practices of Data Visualization
Principles and Practices of Data VisualizationPrinciples and Practices of Data Visualization
Principles and Practices of Data VisualizationKianJazayeri1
 
What To Do For World Nature Conservation Day by Slidesgo.pptx
What To Do For World Nature Conservation Day by Slidesgo.pptxWhat To Do For World Nature Conservation Day by Slidesgo.pptx
What To Do For World Nature Conservation Day by Slidesgo.pptxSimranPal17
 
World Economic Forum Metaverse Ecosystem By Utpal Chakraborty.pdf
World Economic Forum Metaverse Ecosystem By Utpal Chakraborty.pdfWorld Economic Forum Metaverse Ecosystem By Utpal Chakraborty.pdf
World Economic Forum Metaverse Ecosystem By Utpal Chakraborty.pdfsimulationsindia
 
Learn How Data Science Changes Our World
Learn How Data Science Changes Our WorldLearn How Data Science Changes Our World
Learn How Data Science Changes Our WorldEduminds Learning
 
Decoding the Heart: Student Presentation on Heart Attack Prediction with Data...
Decoding the Heart: Student Presentation on Heart Attack Prediction with Data...Decoding the Heart: Student Presentation on Heart Attack Prediction with Data...
Decoding the Heart: Student Presentation on Heart Attack Prediction with Data...Boston Institute of Analytics
 
Bank Loan Approval Analysis: A Comprehensive Data Analysis Project
Bank Loan Approval Analysis: A Comprehensive Data Analysis ProjectBank Loan Approval Analysis: A Comprehensive Data Analysis Project
Bank Loan Approval Analysis: A Comprehensive Data Analysis ProjectBoston Institute of Analytics
 

Último (20)

Decoding Movie Sentiments: Analyzing Reviews with Data Analysis model
Decoding Movie Sentiments: Analyzing Reviews with Data Analysis modelDecoding Movie Sentiments: Analyzing Reviews with Data Analysis model
Decoding Movie Sentiments: Analyzing Reviews with Data Analysis model
 
Insurance Churn Prediction Data Analysis Project
Insurance Churn Prediction Data Analysis ProjectInsurance Churn Prediction Data Analysis Project
Insurance Churn Prediction Data Analysis Project
 
Data Factory in Microsoft Fabric (MsBIP #82)
Data Factory in Microsoft Fabric (MsBIP #82)Data Factory in Microsoft Fabric (MsBIP #82)
Data Factory in Microsoft Fabric (MsBIP #82)
 
NO1 Certified Black Magic Specialist Expert Amil baba in Lahore Islamabad Raw...
NO1 Certified Black Magic Specialist Expert Amil baba in Lahore Islamabad Raw...NO1 Certified Black Magic Specialist Expert Amil baba in Lahore Islamabad Raw...
NO1 Certified Black Magic Specialist Expert Amil baba in Lahore Islamabad Raw...
 
SMOTE and K-Fold Cross Validation-Presentation.pptx
SMOTE and K-Fold Cross Validation-Presentation.pptxSMOTE and K-Fold Cross Validation-Presentation.pptx
SMOTE and K-Fold Cross Validation-Presentation.pptx
 
The Power of Data-Driven Storytelling_ Unveiling the Layers of Insight.pptx
The Power of Data-Driven Storytelling_ Unveiling the Layers of Insight.pptxThe Power of Data-Driven Storytelling_ Unveiling the Layers of Insight.pptx
The Power of Data-Driven Storytelling_ Unveiling the Layers of Insight.pptx
 
IBEF report on the Insurance market in India
IBEF report on the Insurance market in IndiaIBEF report on the Insurance market in India
IBEF report on the Insurance market in India
 
Data Analysis Project: Stroke Prediction
Data Analysis Project: Stroke PredictionData Analysis Project: Stroke Prediction
Data Analysis Project: Stroke Prediction
 
Student profile product demonstration on grades, ability, well-being and mind...
Student profile product demonstration on grades, ability, well-being and mind...Student profile product demonstration on grades, ability, well-being and mind...
Student profile product demonstration on grades, ability, well-being and mind...
 
Minimizing AI Hallucinations/Confabulations and the Path towards AGI with Exa...
Minimizing AI Hallucinations/Confabulations and the Path towards AGI with Exa...Minimizing AI Hallucinations/Confabulations and the Path towards AGI with Exa...
Minimizing AI Hallucinations/Confabulations and the Path towards AGI with Exa...
 
Real-Time AI Streaming - AI Max Princeton
Real-Time AI  Streaming - AI Max PrincetonReal-Time AI  Streaming - AI Max Princeton
Real-Time AI Streaming - AI Max Princeton
 
Decoding Patterns: Customer Churn Prediction Data Analysis Project
Decoding Patterns: Customer Churn Prediction Data Analysis ProjectDecoding Patterns: Customer Churn Prediction Data Analysis Project
Decoding Patterns: Customer Churn Prediction Data Analysis Project
 
Data Analysis Project : Targeting the Right Customers, Presentation on Bank M...
Data Analysis Project : Targeting the Right Customers, Presentation on Bank M...Data Analysis Project : Targeting the Right Customers, Presentation on Bank M...
Data Analysis Project : Targeting the Right Customers, Presentation on Bank M...
 
Semantic Shed - Squashing and Squeezing.pptx
Semantic Shed - Squashing and Squeezing.pptxSemantic Shed - Squashing and Squeezing.pptx
Semantic Shed - Squashing and Squeezing.pptx
 
Principles and Practices of Data Visualization
Principles and Practices of Data VisualizationPrinciples and Practices of Data Visualization
Principles and Practices of Data Visualization
 
What To Do For World Nature Conservation Day by Slidesgo.pptx
What To Do For World Nature Conservation Day by Slidesgo.pptxWhat To Do For World Nature Conservation Day by Slidesgo.pptx
What To Do For World Nature Conservation Day by Slidesgo.pptx
 
World Economic Forum Metaverse Ecosystem By Utpal Chakraborty.pdf
World Economic Forum Metaverse Ecosystem By Utpal Chakraborty.pdfWorld Economic Forum Metaverse Ecosystem By Utpal Chakraborty.pdf
World Economic Forum Metaverse Ecosystem By Utpal Chakraborty.pdf
 
Learn How Data Science Changes Our World
Learn How Data Science Changes Our WorldLearn How Data Science Changes Our World
Learn How Data Science Changes Our World
 
Decoding the Heart: Student Presentation on Heart Attack Prediction with Data...
Decoding the Heart: Student Presentation on Heart Attack Prediction with Data...Decoding the Heart: Student Presentation on Heart Attack Prediction with Data...
Decoding the Heart: Student Presentation on Heart Attack Prediction with Data...
 
Bank Loan Approval Analysis: A Comprehensive Data Analysis Project
Bank Loan Approval Analysis: A Comprehensive Data Analysis ProjectBank Loan Approval Analysis: A Comprehensive Data Analysis Project
Bank Loan Approval Analysis: A Comprehensive Data Analysis Project
 

Hidden Gems of Performance Tuning: Hierarchical Profiler and DML Trigger Optimization

  • 1. 1 of 92 Hidden Gems of Performance Tuning: Hierarchical Profiler and DML Trigger Optimization Michael Rosenblum www.dulcian.com
  • 2. 2 of 92 Who Am I? – “Misha” Oracle ACE Co-author of 3 books  PL/SQL for Dummies  Expert PL/SQL Practices  Oracle PL/SQL Performance Tuning Tips & Techniques Known for:  SQL and PL/SQL tuning  Complex functionality  Code generators  Repository-based development
  • 3. 3 of 92 Yet another performance presentation??? NO! Because: I will NOT talk about bind variables  … more than a few [dozen] times  I will NOT mention extra paid options/products.  Well…I am a [database] doctor, not a [salesman?] (c) Star Trek I will NOT be buzzword-compliant  … so you can be [mostly] CLOUD- and EXADATA-free.
  • 4. 4 of 92 Part 1 PL/SQL Profiling
  • 5. 5 of 92 Tuning (CFO Level) Means: Ensuring that available resources are used in the most efficient way:  No wasted resources  No under-utilized resources  Impact: Makes CFO happy when they look at hardware costs
  • 6. 6 of 92 Tuning (Practical Level) Means: MAKING END-USERS HAPPY!
  • 7. 7 of 92 Reality Check End-users DON’T CARE ABOUT:  CPU utilization/disk workload/etc.  Being buzzword-compliant by using the coolest technology stack DO CARE ABOUT:  Being able to run their business  … i.e. monthly report should not take two months to prepare!  Time wasted looking at an hourglass on the screen  … although the notion of “wasted time” can be managed by using various psychological tricks (managing expectations!).
  • 8. 8 of 92 So? It’s all about end-user requests… 3. Application Server 2. Send data from Client to app server 5. Database 6. Return Data from database to app server 1. Client 4. Send data from app server to database 7. Data in Application Server 8. Return data from app server to client 9. Data in client … and time is lost here
  • 9. 9 of 92 Let’s assume…. You’ve proven that IT IS a database problem  ... and not network traffic/slow client/etc.  … and not the number of round trips from the application server! You can modify database-related code  Best case: You know how to use a “thick database approach”  … i.e. you have high level PL/SQL APIs (that call various SQL queries)  …and these APIs are called by everybody else (UI/reports/BI/etc.)  Worst case: If needed, you can add diagnostic PL/SQL calls around SQL.
  • 10. 10 of 92 A Perfect World Database API response API call PROCEDURE p_DoSomething IS BEGIN p_doSomethingElse1; sql_1; p_doSomethingElse2; sql_2; … END;
  • 11. 11 of 92 Less Than Perfect World Database SQL or PL/SQL Application Server void doSomething { … doSomethingElse; … }
  • 12. 12 of 92 THE Problem Database is spending too much time doing something: Perfect Case [one SQL statement that does not contain any user-defined functions]  Many monitoring mechanisms  Many ways to adjust  Lots of coverage Real case [combination of SQL and PL/SQL]  Hierarchical in its nature  something is calling something that is calling something else  Cannot be represented as a sequence of simple cases!
  • 13. 13 of 92 The Hero PL/SQL Hierarchical Profiler
  • 14. 14 of 92 What can it do for you? PL/SQL Hierarchical Profiler: Gathers hierarchical statistics of all calls (both SQL and PL/SQL) for the duration of the monitoring  … into a portable trace file Has powerful aggregation utilities  … both within the database and using a command-line interface Available since Oracle 11.1 [replaced PL/SQL Profiler]  … and constantly improved (significantly changed in 18c!)
  • 15. 15 of 92 Introductory Case Background: You have multiple PL/SQL program units calling each other that have SQL statements within them. Problem: You need to know where time is wasted and where it would be best to spend time on tuning.
  • 16. 16 of 92 Intro (1) SQL> CREATE DIRECTORY IO AS 'C:IO'; SQL> exec dbms_hprof.start_profiling (location=>'IO',filename=>'HProf.txt'); SQL> DECLARE 2 PROCEDURE p_doSomething (pi_empno NUMBER) IS 3 BEGIN 4 dbms_lock.sleep(0.1); 5 END; 6 PROCEDURE p_main IS 7 BEGIN 8 dbms_lock.sleep(0.5); 9 FOR c IN (SELECT * FROM emp) LOOP 10 p_doSomething(c.empno); 11 END LOOP; 12 END; 13 BEGIN 14 p_main(); 15 END; 16 / SQL> exec dbms_hprof.stop_profiling; Destination folder: WRITE is enough Spend time
  • 17. 17 of 92 Intro (2) Raw file (C:IOHProf.txt) is not very readable… P#V PLSHPROF Internal Version 1.0 P#! PL/SQL Timer Started P#C PLSQL."".""."__plsql_vm" P#X 8 P#C PLSQL."".""."__anonymous_block" P#X 6 P#C PLSQL."".""."__anonymous_block.P_MAIN"#980980e97e42f8ec #6 P#X 63 P#C PLSQL."SYS"."DBMS_LOCK"::9."__pkg_init" P#X 7 P#R P#X 119 P#C PLSQL."SYS"."DBMS_LOCK"::11."SLEEP"#e17d780a3c3eae3d #197 P#X 500373 P#R P#X 586 P#C SQL."".""."__sql_fetch_line9" #9."4ay6mhcbhvbf2" P#! SELECT * FROM SCOTT.EMP P#X 3791 P#R P#X 17 <<… and so on …>> Call Elapsed time between events Return from sub-program
  • 18. 18 of 92 Intro (3) … but you can and make it readable via the command-line utility: C:Utl_FileIO>plshprof -output hprof_intro HProf.txt PLSHPROF: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production [8 symbols processed] [Report written to 'hprof_intro.html'] <Show files>
  • 19. 19 of 92 Intro Findings The results are: All of the time is spent in DBMS_LOCK.SLEEP  …There are no descendants! When we drill down, the SLEEP procedure was called from multiple parent modules!  This is important because, in one case, time spent is 0.1 per call and in the other is 0.5 per call. Oracle 12.2+  SQL ID and first 50 characters of SQL text  Very nice, especially in the case of Dynamic SQL Many sorting/reporting options!
  • 20. 20 of 92 Intro (4) … and also you can analyze the trace file via PL/SQL APIs  Pro: easier to link with SQL statistics  Contra: need extra READ privilege on the directory + need to create tables beforehand [11g,12c – script only / 18c,19с – API or script] DECLARE runid NUMBER; BEGIN runid := DBMS_HPROF.analyze('IO','HProf.txt'); DBMS_OUTPUT.PUT_LINE('runid = ' || runid); END; / DBMSHP_RUNS Run_ID PK … DBMSHP_Parent_Child_Info Run_ID PK ParentSymID FK ChildSymID FK … DBMSHP_Function_Info SymbolID PK Run_ID FK Module Type Function …
  • 21. 21 of 92 Intro (5) … btw, ANALYZE has some nice options:  Trace only specific entries runid := DBMS_HPROF.analyze('IO','HProf.txt', trace=> '"SCOTT"."F_CHANGE_TX"');  Trace up to N occurrences runid := DBMS_HPROF.analyze('IO','HProf.txt', collect => 20, trace=> '"SCOTT"."F_CHANGE_TX"');  Trace starting from N-th occurrence runid := DBMS_HPROF.analyze('IO','HProf.txt', skip =>1, trace=> '"SCOTT"."F_CHANGE_TX"');
  • 22. 22 of 92 18c and Up – no RAW Files (1) Raw data can be generated into tables directly: DBMS_HPROF.Create_Tables – new API to create all tables  script dbmshptab.sql still exists, but considered deprecated  API has FORCE_IT parameter  if TRUE – drop/recreate tables Pro: Only limited privileges are needed to run performance analysis directly in PROD (no file access at all!) Contra: Harder to move off-site for a third-party review Data volume could get out of hands
  • 23. 23 of 92 18c and Up – no RAW Files (2) DECLARE trace_id number; runid number; PROCEDURE p_doSomething (pi_empno NUMBER) IS BEGIN dbms_lock.sleep(0.1); END; PROCEDURE p_main IS BEGIN dbms_lock.sleep(0.5); FOR c IN (SELECT * FROM scott.emp) LOOP p_doSomething(c.empno); END LOOP; END; BEGIN trace_id := dbms_hprof.start_profiling ; p_main(); dbms_hprof.stop_profiling; runid:=dbms_hprof.analyze(trace_id); dbms_output.put_line('RunId:'||runid); END; Runtime ID No files! Persistent ID
  • 24. 24 of 92 True Story #1: Typical Hierarchical Profiler Use
  • 25. 25 of 92 Typical Situation Help-desk client’s performance complaints: Developer checked 10046 trace and couldn’t find anything suspicious I noticed that the core query contains a user-defined PL/SQL function. Action: Wrap suspicious call in HProf start/stop in TEST instance (with the same volume of data)
  • 26. 26 of 92 Suspect SQL> exec dbms_hprof.start_profiling ('IO', 'HProf_Case1.txt'); SQL> declare 2 v_tx varchar2(32767); 3 begin 4 select listagg(owner_tx,',') within group (order by 1) 5 into v_tx 6 from ( 7 select distinct scott.f_change_tx(owner) owner_tx 8 from scott.test_tab 9 ); 10 end; 11 / SQL> exec dbms_hprof.stop_profiling; 1. Only 26 owners! 2. Function is doing basic formatting
  • 27. 27 of 92 Profile 50k calls?! Here is my time! <Show files>
  • 28. 28 of 92 Findings Problem:  Time is wasted on very cheap function which is fired lots and lots of times  … because the original developer “guessed” at the query behavior  … i.e. he knew function was doing basic formatting, so the output would also be distinct  … but forgot to tell that to the CBO  GIGO! Solution:  Rewrite query in a way that helps the CBO  … and remind all developers:  The number of function calls in SQL will surprise you if you don’t measure them.
  • 29. 29 of 92 Fix SQL> exec dbms_hprof.start_profiling ('IO', 'HProf_Case1_fix.txt'); SQL> declare 2 v_tx varchar2(32767); 3 begin 4 select listagg(owner_tx,',') within group (order by 1) 5 into v_tx 6 from ( 7 select scott.f_change_tx(owner) owner_tx 8 from (select distinct owner 9 from scott.test_tab) 10 ); 11 end; 12 / SQL> exec dbms_hprof.stop_profiling Filter first! <Show files>
  • 30. 30 of 92 Updated Profile 28 times faster! 26 calls <Show files>
  • 31. 31 of 92 Extra Test: SQL in Java and SQL*Plus
  • 32. 32 of 92 Running directly from Java? Good news: It works! You can run multiple statements between START and STOP Bad news: No SQL IDs if they run directly (at least we couldn’t get it)  confused statistics   Environment: JDeveloper 11g
  • 33. 33 of 92 Java Sample String sql = "begin dbms_hprof.start_profiling (location=>'IO',filename=>'Case1a.txt'); end;"; CallableStatement stmt = conn.prepareCall(sql); stmt.execute(); PreparedStatement stmt2 = conn.prepareStatement("select listagg(owner_tx,',') within group (order by 1) result n" + "from (select distinct scott.f_change_tx(owner) owner_txn" + " from scott.test_tab) A "); stmt2.execute(); stmt2 = conn.prepareStatement("select listagg(owner_tx,',') within group (order by 1) n" + "from (select distinct scott.f_change_tx(owner) owner_txn" + " from scott.test_tab) B "); stmt2.execute(); sql = "begin dbms_hprof.stop_profiling; end;"; stmt = conn.prepareCall(sql); stmt.execute(); Difference! <Show files>
  • 34. 34 of 92 Impact - Java 100k Calls No SQL IDs <Show files>
  • 35. 35 of 92 Running directly from SQL*Plus? Bad news: the same problem with multiple statements: SQL> exec dbms_hprof.start_profiling 2 (location=>'IO',filename=>'Case1b_SQLPlus.txt'); SQL> select listagg(owner_tx,',') within group (order by 1) result 2 from (select distinct scott.f_change_tx(owner) owner_tx 3 from scott.test_tab a); ... SQL> select listagg(owner_tx,',') within group (order by 1) 2 from (select distinct scott.f_change_tx(owner) owner_tx 3 from scott.test_tab b); ... SQL> exec dbms_hprof.stop_profiling;
  • 36. 36 of 92 Impact – SQL*Plus 100k Calls <Show files> No SQL IDs (even in 19c)
  • 37. 37 of 92 True Story #2: Unexpected Usage
  • 38. 38 of 92 Background Third-party module code is slow Functionality: Take some tables and columns /return formatted CLOB The code is wrapped Original developers don’t want to accept the blame. Action: Gather as many statistics about the module as you can Wrap suspicious call in HProf start/stop
  • 39. 39 of 92 Statistics (1) SQL> exec runstats_pkg.rs_start; SQL> DECLARE 2 v_CL CLOB; 3 BEGIN 4 v_cl :=wrapped_pkg.f_getdata_cl('ename','emp'); 5 dbms_output.put_line('length:'||LENGTH(v_cl)); 6 END; 7 / length:84 SQL> exec runstats_pkg.rs_middle; SQL> DECLARE 2 v_CL CLOB; 3 BEGIN 4 v_cl :=wrapped_pkg.f_getdata_cl('object_name','test_tab'); 5 dbms_output.put_line('length:'||LENGTH(v_cl)); 6 END; 7 / length:1247887 50000 rows Wrapped module 14 rows
  • 40. 40 of 92 Statistics (2) SQL> exec runstats_pkg.rs_stop; Run1 ran in 0 cpu hsecs Run2 ran in 3195 cpu hsecs run 1 ran in 0% of the time Name Run1 Run2 Diff ... STAT...physical reads direct (lob) 13 49,991 49,978 STAT...physical reads direct temporary tablespace 13 49,991 49,978 STAT...lob writes 14 50,000 49,986 STAT...physical writes direct temporary tablespace 14 50,145 50,131 STAT...physical writes direct (lob) 14 50,145 50,131 Direct Temp I/O?!?!
  • 41. 41 of 92 Profile for the Slow Case Explicit “create temp” 50k calls
  • 42. 42 of 92 Analysis Problem #1: Direct IO for all temporary LOB operations Could happen only if LOB variable is initiated as NOCACHE via DBMS_LOB.createTemporary Problem #2: IO operation for every row in conjunction with fetch for every row Could happen only if DBMS_LOB.writeAppend is called within the loop
  • 43. 43 of 92 Unwrapped code (FYI) FUNCTION f_getData_cl(i_column_tx VARCHAR2, i_table_tx VARCHAR2) RETURN CLOB IS v_cl CLOB; v_tx VARCHAR2(32767); v_cur SYS_REFCURSOR; BEGIN dbms_lob.createTemporary(v_cl,false,dbms_lob.call); OPEN v_cur FOR 'SELECT '|| dbms_assert.simple_sql_name(i_column_tx)||' field_tx'|| ' FROM '||dbms_assert.simple_sql_name(i_table_tx); LOOP FETCH v_cur into v_tx; EXIT WHEN v_cur%notfound; dbms_lob.writeAppend(v_cl,length(v_tx)+1,v_tx||'|'); END LOOP; CLOSE v_cur; RETURN v_cl; END; Issue #1: no cache Issue #2: no buffer <Show optimized code if time permits>
  • 44. 44 of 92 Part1: Summary End users only care that their requests come back quickly … and not about CPU/Memory/IO utilization Yes, sometimes it IS the database  … but 90% of time it isn’t  PL/SQL Hierarchical profiler lets you see the system from the end-user angle and find real performance issues …i.e. request-driven (with drill-down option) PL/SQL Hierarchical profiler is constantly improving .. i.e. don’t forget to read “New Features” guide!
  • 45. 45 of 92 Part 2 Trigger Discipline
  • 46. 46 of 92 Handle with care… Triggers Given a lot of bad publicity  …Some Oracle gurus think that they should never have existed! Getting more complex with each Oracle release  … Cross-edition triggers, compound triggers, event triggers… Constantly misused  … But can be very useful when applied appropriately!
  • 47. 47 of 92 1.DML triggers
  • 48. 48 of 92 Danger Area Developers have different reasons to use DML triggers … but very few are valid. Problems start when triggers are asked to perform complex tasks … although, there is nothing wrong with enforcing the format of a Social Security Number field (for example). Any solution that requires a DML trigger to touch data outside of the current row is questionable.
  • 49. 49 of 92 Anti-Pattern Requirement: A person can have a number of mailing addresses. Only one is designated to be “current.” Common (wrong!) solution: Column Current_YN is added to ADDRESS table. Complex trigger-based solutions are needed to avoid ORA-04091 “Table is mutating”  … and yes, I know about compound triggers 
  • 50. 50 of 92 No Triggers Here! Correct Solution: Add reverse key to PERSON Person Person_ID PK Name_TX PrimaryAddress_FK FK Address Address_ID PK Person_FK FK City_TX …. 0..1 0..* 0..* 0..1 >> Person may have address >> << One of the addresses is defined as current <<
  • 51. 51 of 92 1.1. Constraints vs. Triggers
  • 52. 52 of 92 Single Condition Same business logic/different implementation? -- option 1: ALTER TABLE emp add CONSTRAINT emp_sal_ck CHECK (sal<=5000); -- option 2: CREATE OR REPLACE TRIGGER emp_row_biu BEFORE INSERT OR UPDATE ON emp FOR EACH ROW BEGIN IF :NEW.sal>5000 THEN raise_application_error(-20001, 'salary cannot exceed 5000'); END IF; END;
  • 53. 53 of 92 With Constraint… SQL> ALTER TABLE emp add CONSTRAINT emp_sal_ck CHECK (sal<=5000); SQL> SET AUTOTRACE TRACEONLY EXPLAIN SQL> SELECT * FROM emp WHERE sal > 10000; Execution Plan ---------------------------------------------------------- Plan hash value: 1341312905 ------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes| Cost (%CPU)| Time ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1| 38| 0 (0)| |* 1 | FILTER | | | | | |* 2 | TABLE ACCESS FULL| EMP | 1| 38| 3 (0)| 00:00:01 ------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(NULL IS NOT NULL) 2 - filter("SAL">10000) Don’t do ANYTHING!
  • 54. 54 of 92 Without Constraint… SQL> ALTER TABLE emp DISABLE CONSTRAINT emp_sal_ck; SQL> select * from emp where sal > 10000; Execution Plan ---------------------------------------------------------- Plan hash value: 3956160932 ------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time ------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 38 | 3 (0)| 00:00:01 |* 1 | TABLE ACCESS FULL| EMP | 1 | 38 | 3 (0)| 00:00:01 ------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("SAL">10000) Full table scan!
  • 55. 55 of 92 Single Condition Summary Check constraints are part of metadata  CBO impact … as long as they are enabled and validated. Triggers hide business logic from Oracle, but they give you more power. What if you need to check multiple conditions?
  • 56. 56 of 92 Multiple Conditions - Constraints SQL> ALTER TABLE emp 2 ADD CONSTRAINT emp_comm_ck CHECK (comm<=2000); SQL> UPDATE emp 2 SET sal=10000, 3 comm=3000 4 WHERE empno=7902; UPDATE emp SET sal=10000,comm=3000 WHERE empno=7902 * ERROR at line 1: ORA-02290: check constraint(SCOTT.EMP_COMM_CK) violated Second condition Only one error! Two violations
  • 57. 57 of 92 Multiple Conditions – Trigger SQL> CREATE OR REPLACE TRIGGER emp_row_biu 2 BEFORE INSERT OR UPDATE ON emp 3 FOR EACH ROW 4 DECLARE 5 v_error_tx VARCHAR2(32767); 6 BEGIN 7 IF :NEW.sal>5000 THEN 8 v_error_tx:=v_error_tx||CHR(10)|| 9 '* salary cannot exceed 5000'; 10 END IF; 11 IF :NEW.comm>2000 THEN 12 v_error_tx:=v_error_tx||CHR(10)|| 13 '* commissions cannot exceed 2000'; 14 END IF; 15 IF v_error_tx IS NOT NULL THEN 16 raise_application_error(-20001,'Errors:'||v_error_tx); 17 END IF; 18 end; 19 / Aggregator
  • 58. 58 of 92 Multiple Conditions - Constraints SQL> UPDATE emp 2 SET sal=10000,comm=3000 3 WHERE empno=7902; UPDATE emp SET sal=10000,comm=3000 WHERE empno=7902 * ERROR at line 1: ORA-20001: Errors: * salary cannot exceed 5000 * commissions cannot exceed 2000 ORA-06512: at "SCOTT.EMP_ROW_BIU", line 15 ORA-04088: error during execution of trigger 'SCOTT.EMP_ROW_BIU' Both errors!
  • 59. 59 of 92 Multiple Conditions - Summary Triggers: Allow multiple errors to be propagated. Allow human-readable error messages. Repeated warning: Implementing cross-row conditions (“Salary Cannot exceed 150% of the average in the department”) as triggers is very dangerous!  … just Google “read consistency”
  • 60. 60 of 92 1.2 Default Values
  • 61. 61 of 92 Populating Sequence ID Available options: Explicitly pass into INSERT Before-INSERT trigger Default=SEQUENCE.NEXTVAL (Oracle 12c+)
  • 62. 62 of 92 Sample Set CREATE SEQUENCE test_trigger_seq; CREATE TABLE test_trigger_tab1 (a NUMBER, b VARCHAR2(1)); CREATE OR REPLACE TRIGGER test_trigger_tab1_bi BEFORE INSERT ON test_trigger_tab1 FOR EACH ROW DISABLE BEGIN IF :NEW.a IS NULL THEN :NEW.a:=test_trigger_seq.NEXTVAL; END IF; END; Starting disabled
  • 63. 63 of 92 Compare Pre-12c Options SQL> exec runstats_pkg.rs_start; SQL> ALTER TRIGGER test_trigger_tab1_bi ENABLE; SQL> BEGIN 2 FOR i IN 1..10000 LOOP 3 INSERT INTO test_trigger_tab1(b) VALUES ('X'); 4 END LOOP; 5 END; 6 / SQL> exec runstats_pkg.rs_middle; SQL> ALTER TRIGGER test_trigger_tab1_bi DISABLE; SQL> BEGIN 2 FOR i IN 1..10000 LOOP 3 INSERT INTO test_trigger_tab1(a,b) VALUES(test_trigger_seq.NEXTVAL,'X') 4 END LOOP; 5 END; 6 / SQL> exec runstats_pkg.rs_stop; Run1 ran in 281 cpu hsecs Run2 ran in 172 cpu hsecs Name Run1 Run2 Diff STAT...recursive cpu usage 268 147 -121 STAT...recursive calls 20,641 10,594 -10,047 Trigger overhead
  • 64. 64 of 92 Pre-12c vs. 12c SQL> exec runstats_pkg.rs_start; SQL> ALTER TABLE test_trigger_tab1 2 MODIFY a DEFAULT test_trigger_seq.NEXTVAL; <<< ... 10 000 inserts ... >>> SQL> exec runstats_pkg.rs_middle; SQL> ALTER TABLE test_trigger_tab1 MODIFY a DEFAULT NULL; SQL> BEGIN 2 FOR i IN 1..10000 LOOP 3 INSERT INTO test_trigger_tab1(a,b) VALUES (test_trigger_seq.NEXTVAL,'X'); 5 END LOOP; 6 END; 7 / SQL> exec runstats_pkg.rs_stop; Run1 ran in 178 cpu hsecs Run2 ran in 157 cpu hsecs run 1 ran in 113.38% of the time Name Run1 Run2 Diff STAT...recursive cpu usage 164 136 -28 Much closer!
  • 65. 65 of 92 2. INSTEAD-OF Triggers
  • 66. 66 of 92 INSTEAD OF Trigger Issues DML against views with INSTEAD OF triggers behave differently in comparison to regular DML … especially for function-based views. Developers often misunderstand how these triggers work … and mishandle logical primary keys. Proper handling of UPDATEs require deep understanding of Oracle UNDO mechanisms.
  • 67. 67 of 92 2.1 DMLs Against Function-Based Views
  • 68. 68 of 92 Test Case (1) CREATE TYPE test_tab_ot AS OBJECT (owner_tx VARCHAR2(30), name_tx VARCHAR2(30), object_id NUMBER, type_tx VARCHAR2(30)); CREATE TYPE test_tab_nt IS TABLE OF test_tab_ot; CREATE FUNCTION f_searchTestTab_tt (i_type_tx VARCHAR2) RETURN test_tab_nt IS v_out_tt test_tab_nt; begin SELECT test_tab_ot(owner, object_name, object_id, object_type) BULK COLLECT INTO v_out_tt FROM test_tab WHERE object_type = i_type_tx; dbms_output.put_line('Inside f_searchTestTab_tt:'||v_out_tt.count); RETURN v_out_tt; END;
  • 69. 69 of 92 Test Case (2) create or replace view v_search_table as select * from table(f_searchtesttab_tt('TABLE')); create or replace trigger v_search_table_iiud instead of insert or update or delete on v_search_table begin if inserting then dbms_output.put_line('Insert'); elsif updating then dbms_output.put_line('Update'); elsif deleting then dbms_output.put_line(‘Delete'); end if; end;
  • 70. 70 of 92 DML Check SQL> INSERT INTO v_search_table (object_id, name_tx) 2 VALUES (-1,'A'); Insert 1 row created. SQL> UPDATE v_search_table SET name_tx = 'Test‘ 2 WHERE object_id = 5; Inside f_searchTestTab_tt:1541 Update 1 row updated. SQL> DELETE FROM v_search_table WHERE object_id = 5; Inside f_searchTestTab_tt:1541 Delete 1 row deleted. Function is not fired! Process all to update one?
  • 71. 71 of 92 Side-Effect of Function-Based Views Real problem: WHERE clauses on function-based views are extremely inefficient. Solution: Pass conditions as parameters into the function.
  • 72. 72 of 92 Parameterized View (1) CREATE PACKAGE global_pkg IS v_object_id NUMBER; END; CREATE FUNCTION f_searchTestTab_tt (i_type_tx varchar2) RETURN test_tab_nt is v_out_tt test_tab_nt; BEGIN IF global_pkg.v_object_id IS NULL THEN SELECT test_tab_ot(owner, object_name, object_id, object_type) BULK COLLECT INTO v_out_tt FROM test_tab WHERE object_type = i_type_tx; ELSE SELECT test_tab_ot(owner, object_name, object_id, object_type) BULK COLLECT INTO v_out_tt FROM test_tab WHERE object_id = global_pkg.v_object_id; END IF; dbms_output.put_line ('Inside f_searchTestTab_tt:'||v_out_tt.count); RETURN v_out_tt; END; Usage (if needed) Global parameter
  • 73. 73 of 92 Parameterized View (2) SQL> BEGIN global_pkg.v_object_id:=5; END; 2 / SQL> UPDATE v_search_table SET name_tx = 'Test' 2 WHERE object_id = 5; Inside f_searchTestTab_tt:1 Update 1 row updated. SQL> DELETE FROM v_search_table WHERE object_id = 5; Inside f_searchTestTab_tt:1 Delete 1 row deleted.
  • 74. 74 of 92 Parameterized View (3) SQL> exec runstats_pkg.rs_start; SQL> BEGIN 2 global_pkg.v_object_id:=NULL; 3 FOR i IN 1..100 LOOP 4 UPDATE v_search_table SET name_tx = 'Test'||i 5 WHERE object_id = 5; 6 END LOOP; 7 END; 8 / SQL> exec runstats_pkg.rs_middle; SQL> BEGIN 2 global_pkg.v_object_id:=5; 3 FOR i IN 1..100 LOOP 4 UPDATE v_search_table SET name_tx = 'Test'||i 5 WHERE object_id = 5; 6 END LOOP; 7 END; 8 / SQL> exec runstats_pkg.rs_stop; Run1 ran in 181 cpu hsecs Run2 ran in 28 cpu hsecs run 1 ran in 646.43% of the time 5x improvement
  • 75. 75 of 92 2.2 Dangers of Logical Primary Keys
  • 76. 76 of 92 The Real Story Synthetic primary keys on views Sometimes required by front-end environments (to uniquely identify the row in the cache) Extremely dangerous if blindly used for INSERT/UPDATE/DELETE
  • 77. 77 of 92 Test Case CREATE OR REPLACE VIEW v_test_tab AS SELECT 'Main|'||object_id pk_tx, a.* FROM test_tab_main a UNION ALL SELECT 'Other|'||object_id pk_tx, a.* FROM test_tab_other a;
  • 78. 78 of 92 Performance Impact SQL> set autotrace traceonly explain SQL> UPDATE v_test_tab 2 SET object_name='Test' 3 WHERE pk_tx='Main|1'; 1 row updated. Execution Plan ---------------------------------------------------------- Plan hash value: 3568876726 ------------------------------------------------------------------------- |Id| Operation | Name | Rows | Bytes | Cost (%CPU)| ------------------------------------------------------------------------- | 0| UPDATE STATEMENT | | 500 | 45500 | 236 (1)| | 1| UPDATE | V_TEST_TAB | | | | | 2| VIEW | V_TEST_TAB | 500 | 45500 | 236 (1)| | 3| UNION-ALL | | | | | |*4| TABLE ACCESS FULL| TEST_TAB_MAIN | 15 | 330 | 9 (0)| |*5| TABLE ACCESS FULL| TEST_TAB_OTHER | 485 | 14550 | 227 (1)| --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter('Main|'||TO_CHAR("OBJECT_ID")='Main|1') 5 - filter('Other|'||TO_CHAR("OBJECT_ID")='Main|1') Full-table scans!
  • 79. 79 of 92 2.3 Handling UPDATEs
  • 80. 80 of 92 Resource Issues Problem  INSTEAD-OF UPDATE triggers often reference all columns of the underlying tables  … instead of trying to figure out what has been changed.  UNDO is generated for all columns mentioned in the UPDATE statement  … irrelevant whether they were changed or not  … which causes major I/O overhead Alternative:  Use Dynamic SQL to modify only changed columns  … i.e. trade off CPU utilization for better I/O!
  • 81. 81 of 92 Regular Trigger create or replace trigger v_test_tab_iu instead of update on v_test_tab begin if :new.object_type='TABLE' then update test_tab_main set owner=:new.owner, object_name=:new.object_name, subobject_name=:new.subobject_name, object_type=:new.object_type, created=:new.created, last_ddl_time=:new.last_ddl_time, timestamp=:new.timestamp, status=:new.status, temporary=:new.temporary, generated=:new.generated, secondary=:new.secondary, namespace=:new.namespace, edition_name=:new.edition_name, sharing=:new.sharing, editionable=:new.editionable, oracle_maintained=:new.oracle_maintained where object_id=:old.object_id; else update test_tab_other set << the same list of columns as above >> where object_id=:old.object_id; end if; end;
  • 82. 82 of 92 Dynamic SQL Trigger (1) create or replace trigger v_test_tab_dynamic_iu instead of update on v_test_tab declare v_main_rec test_tab_main%rowtype; v_mainupdate_tx varchar2(32767); v_other_rec test_tab_other%rowtype; v_otherupdate_tx varchar2(32767); begin if :new.object_type='table' then -- compare old/new for each attribute if :old.object_name is null and :new.object_name is not null or :old.object_name is not null and :new.object_name is null or :old.object_name!=:new.object_name then v_main_rec.object_name:=:new.object_name; v_mainupdate_tx:=v_mainupdate_tx|| case when v_mainupdate_tx is not null then ',' else null end||chr(10)|| ' object_name=v_rec.object_name'; end if; ... Store new value (if changed)
  • 83. 83 of 92 Dynamic SQL Trigger (2) v_main_rec.object_id:=:old.object_id; v_mainupdate_tx:= 'declare '||chr(10)|| ' v_rec test_tab_main%rowtype:=:1;'||chr(10)|| 'begin '||chr(10)|| ' update test_tab_main ' ||chr(10)|| ' set '||v_mainupdate_tx||chr(10)|| ' where object_id=v_rec.object_id;'||chr(10)|| 'end;'; execute immediate v_mainupdate_tx using v_main_rec; else << the same logic as above for test_tab_other >> end if; end;
  • 84. 84 of 92 Performance Tradeoff SQL> exec runstats_pkg.rs_start; <<disable Dynamic trigger, enable regular trigger>> SQL> begin 2 for i in 1..10000 loop 3 UPDATE v_test_tab SET object_name='Test'||i WHERE object_id = 5; 4 end loop; 5 END; 6 / SQL> exec runstats_pkg.rs_middle; <<enable Dynamic trigger, disable regular trigger and rerun the same logic>> SQL> exec runstats_pkg.rs_stop; Run1 ran in 390 cpu hsecs Run2 ran in 496 cpu hsecs run 1 ran in 78.63% of the time Name Run1 Run2 Diff STAT...recursive calls 20,329 30,244 9,915 STAT...execute count 20,102 30,095 9,993 STAT...undo change vector size 2,495,476 938,552 -1,556,924 STAT...redo size 5,820,096 2,772,332 -3,047,764 Run1 latches total versus runs -- difference and pct Run1 Run2 Diff Pct 136,486 184,679 48,193 73.90% More CPU time Much less I/O
  • 85. 85 of 92 3. Compound Triggers (on Views!)
  • 86. 86 of 92 Extending INSTEAD OF You can also create a COMPOUND trigger instead of an INSTEAD OF trigger  Trigger with common program area Impact Pro:  Common program area – possible to share code and global variables  simulating statement-level BEFORE event  Sorry - there is no way to simulate an AFTER event Con:  Yet another place to hide business logic
  • 87. 87 of 92 CREATE OR REPLACE PACKAGE counter_pkg IS v_nr NUMBER:=0; PROCEDURE p_check; procedure p_up; END; CREATE OR REPLACE PACKAGE BODY counter_pkg IS PROCEDURE p_check is BEGIN dbms_output.put_line('Fired:'||counter_pkg.v_nr); counter_pkg.v_nr:=0; END; procedure p_up is begin counter_pkg.v_nr:=counter_pkg.v_nr+1; end; END; create or replace function f_securityCheck_yn return varchar2 is begin counter_pkg.p_up; if sys_context ('USERENV', 'CLIENT_INFO') ='SalMaint' then return 'Y'; else return 'N'; end if; end; Monitoring Tool
  • 88. 88 of 92 CREATE OR REPLACE TRIGGER v_search_table_IIUD INSTEAD OF INSERT OR UPDATE OR DELETE ON v_search_table BEGIN if f_securityCheck_yn = 'Y' then IF INSERTING THEN dbms_output.put_line('Insert'); ELSIF UPDATING THEN dbms_output.put_line('Update'); ELSIF DELETING THEN dbms_output.put_line('Delete'); END IF; end if; END; Option A - Regular
  • 89. 89 of 92 create or replace trigger v_search_table_IIUD_comp for insert or update or delete on v_search_table COMPOUND TRIGGER v_check_yn varchar2(1); instead of each row is begin if v_check_yn is null then v_check_yn:=f_securityCheck_yn; end if; if v_check_yn = 'Y' then IF INSERTING THEN dbms_output.put_line('Insert'); ELSIF UPDATING THEN dbms_output.put_line('Update'); ELSIF DELETING THEN dbms_output.put_line('Delete'); END IF; end if; end instead of each row; end; Option B - Compound Common area Row-level trigger
  • 90. 90 of 92 SQL> alter trigger v_search_table_IIUD_COMP disable; SQL> alter trigger v_search_table_IIUD enable; SQL> update v_search_table set name_tx = 'Test'; Inside f_searchTestTab_tt:1571 1571 rows updated. SQL> exec counter_pkg.p_check; Fired:1571 SQL> alter trigger v_search_table_IIUD_COMP enable; SQL> alter trigger v_search_table_IIUD disable; SQL> update v_search_table set name_tx = 'Test'; Inside f_searchTestTab_tt:1571 1571 rows updated. SQL> exec counter_pkg.p_check; Fired:1 SQL> exec dbms_application_info.set_client_info('SalMaint'); SQL> update v_search_table set name_tx = 'Test'; Inside f_searchTestTab_tt:1571 Update Update .... 1571 rows updated. SQL> exec counter_pkg.p_check; Fired:1 Performance Impact Only one call! Option A - Decline Option B - Decline Option B - Success
  • 91. 91 of 92 Part 2: Summary Triggers are very powerful (as long as they are applied correctly). “Mutating tables” issue usually hides architectural mistakes. … and compound triggers could solve other problems too! INSTEAD OF triggers have to be handled carefully.
  • 92. 92 of 92 Contact Information  Michael Rosenblum – mrosenblum@dulcian.com  Dulcian, Inc. website - www.dulcian.com  Blog: wonderingmisha.blogspot.com