How long does your code take to run? Is it changing? When it is slow, WHY is it slow? Is it your fault, or somebody else’s? Can you prove it? How much faster could your code be? Do you know how to measure the performance of your code as user workloads and data volumes increase? These are fundamental questions about performance, but the vast majority of Oracle application developers can’t answer them. The most popular performance tools available to them—and to the database administrators that run their code in production—are incapable of answering any of these questions. But the Oracle Database can give you exactly what you need to answer these questions and many more. You can know exactly where YOUR CODE is spending YOUR TIME. This session explains how.
This version of the presentation was delivered 2018-04-23 at COLLABORATE 2018 in Las Vegas, Nevada.
14. @CaryMillsap
has to finish quickly.”
click
button
link
row
query
report
job
}{“My
14
This is what performance is.
15. @CaryMillsap
has to finish quickly.”
click
button
link
row
query
report
job
}{“My
15
A performance problem is when it doesn’t.
16. @CaryMillsap 16
“How long does it take?”
Response time (R)
Duration from service request to
service fulfillment.
Sanjay Nancy Ken Jorge
R
t0
t1
R = t1 – t0
Two big questions...
1.How long?
2.Why?
21. @CaryMillsap
1. Focus on the real, actual problem.
2. Catch it in the act.
3. Do the smart thing.
4. Quit when “helping” stops helping.
21
OPTI
M
IZE ANYT
HING
M
ethod
R
Method R
23. @CaryMillsap 23
How do you do this,
when the “it” is your code?
Method R
1. Select the experience you need to improve.
2.Measure its response time (R) in detail.
3.Execute the best net-payoff remedy.
4.Repeat until economically optimal.
60. @CaryMillsap
The definitive guide to accurate, high-precision
measurement of user performance experiences,
for Oracle application developers and database
administrators.
Cary V. Millsap
TM
MeTHOD R
TM
The Guide to
MASTERING
ORACLE
TRACE DATA
Second Edition
REVISED
UPDA
TED
NEW PA
G
ES
1 3 2
60
method-r.com
For more details...
62. @CaryMillsap 62
begin prepare
CPU
latch-related syscall
CPU
end prepare
begin exec
CPU
write(SQLNET_OUT, result_to_client);
end exec
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
latch-related syscall
CPU
write(SQLNET_OUT, result_to_client);
end fetch
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
write(SQLNET_OUT, result_to_client);
write(SQLNET_OUT, more_results);
write(SQLNET_OUT, more_results);
end fetch
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
write(SQLNET_OUT, result_to_client);
write(SQLNET_OUT, more_results);
write(SQLNET_OUT, more_results);
end fetch
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
write(SQLNET_OUT, result_to_client);
write(SQLNET_OUT, more_results);
write(SQLNET_OUT, more_results);
end fetch
read(SQLNET_IN, next_request_from_client);
Oracle kernel code path
This is the
kind of stuff
your code
causes the
Oracle kernel
to do.
63. @CaryMillsap 63
WAIT #42: nam='latch: library cache'…
PARSE #42:c=10000,…
WAIT #42: nam='SQL*Net message to client'…
EXEC #42:c=10000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='latch: cache buffers chains'…
WAIT #42: nam='SQL*Net message to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
Oracle extended SQL trace data
begin prepare
CPU
latch-related syscall
CPU
end prepare
begin exec
CPU
write(SQLNET_OUT, result_to_client);
end exec
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
latch-related syscall
CPU
write(SQLNET_OUT, result_to_client);
end fetch
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
write(SQLNET_OUT, result_to_client);
write(SQLNET_OUT, more_results);
write(SQLNET_OUT, more_results);
end fetch
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
write(SQLNET_OUT, result_to_client);
write(SQLNET_OUT, more_results);
write(SQLNET_OUT, more_results);
end fetch
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
write(SQLNET_OUT, result_to_client);
write(SQLNET_OUT, more_results);
write(SQLNET_OUT, more_results);
end fetch
read(SQLNET_IN, next_request_from_client);
Oracle kernel code path
This is the
kind of
trace data
the kernel
produces.
64. @CaryMillsap 64
WAIT #42: nam='latch: library cache'…
PARSE #42:c=10000,…
WAIT #42: nam='SQL*Net message to client'…
EXEC #42:c=10000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='latch: cache buffers chains'…
WAIT #42: nam='SQL*Net message to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
Oracle extended SQL trace data
Of course,
you don’t
directly get
to see the
kernel code
path.
65. @CaryMillsap 65
WAIT #42: nam='latch: library cache'…
PARSE #42:c=10000,…
WAIT #42: nam='SQL*Net message to client'…
EXEC #42:c=10000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='latch: cache buffers chains'…
WAIT #42: nam='SQL*Net message to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
Oracle extended SQL trace data
...Or that
helpful grid
that I drew
for you.
66. @CaryMillsap 66
WAIT #42: nam='latch: library cache'…
PARSE #42:c=10000,…
WAIT #42: nam='SQL*Net message to client'…
EXEC #42:c=10000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='latch: cache buffers chains'…
WAIT #42: nam='SQL*Net message to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
Oracle extended SQL trace data
All you
get to see
is this.
67. @CaryMillsap
WAIT #42: nam='latch: library cache'…
PARSE #42:c=10000,…
WAIT #42: nam='SQL*Net message to client'…
EXEC #42:c=10000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='latch: cache buffers chains'…
WAIT #42: nam='SQL*Net message to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
WAIT #42: nam='SQL*Net message to client'…
WAIT #42: nam='SQL*Net more data to client'…
WAIT #42: nam='SQL*Net more data to client'…
FETCH #42:c=20000,…
WAIT #42: nam='SQL*Net message from client'…
67
Oracle extended SQL trace dataOracle kernel code path
begin prepare
CPU
latch-related syscall
CPU
end prepare
begin exec
CPU
write(SQLNET_OUT, result_to_client);
end exec
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
latch-related syscall
CPU
write(SQLNET_OUT, result_to_client);
end fetch
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
write(SQLNET_OUT, result_to_client);
write(SQLNET_OUT, more_results);
write(SQLNET_OUT, more_results);
end fetch
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
write(SQLNET_OUT, result_to_client);
write(SQLNET_OUT, more_results);
write(SQLNET_OUT, more_results);
end fetch
read(SQLNET_IN, next_request_from_client);
begin fetch
CPU
write(SQLNET_OUT, result_to_client);
write(SQLNET_OUT, more_results);
write(SQLNET_OUT, more_results);
end fetch
read(SQLNET_IN, next_request_from_client);
You can learn
to envision the
kernel’s code
path that
motivated your
trace file.
86. @CaryMillsap
BASELINE: BAD
for each invoice number {
cursor = parse(“select ...where invoice_number = ” + number);
exec(cursor);
loop over the result set to fetch all the rows;
}
FIX 1 “Hey, let’s use bind variables”:
for each invoice number {
cursor = parse(“select ...where invoice_number = :a1”);
exec(cursor, number);
loop over the result set to fetch all the rows;
}
86
STILL BAD
A little better, but still really awful:
• Uses too much CPU for PARSE calls
• Serialization on library cache latches
• Maybe, too many network round-trips