Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Innovative Specifications for Better Performance Logging and Monitoring

448 views

Published on

Imagine a car with no speedometer. There are speed limit signs and policemen all around with radar guns waiting to catch you speeding, but you have no way of knowing how fast you're going. Of course, a car like this has no openable hood (no bonnet), so to change the air filter, you have to hire a specialist to saw into the body of your car. A car like this would be preposterous. Yet people write software like this all the time.

The Oracle Database has some of the best performance logging features built into it of any software in the world. You can use it with any application—even applications that were built without logging and monitoring in mind. But you can go SO much further if you bother to include some performance logging features in your application. In this session, I explain Oracle's extended SQL tracing feature and describe how to enable and disable it. Then I show some innovative ideas that will help you design and build database applications that are easier to monitor, manage, and maintain throughout the software development life cycle.

Published in: Data & Analytics
  • Be the first to comment

Innovative Specifications for Better Performance Logging and Monitoring

  1. 1. @CaryMillsap Innovative Specifications for Better Performance Logging and Monitoring Cary Millsap Cintra Software and Services · Method R Corporation @CaryMillsap #Kscope18 Walt Disney World Dolphin Resort, Orlando, Florida 9:00a–10:00a Tuesday 12 June 2018 1
  2. 2. 2@CaryMillsap 2020 2015 2010 2005 2000 1995 1990 1985 100 45 6 3 hotsos Method R TM Optimal Flexible Architecture Oracle APS System Pe ormance Group Method R Profiler Method R Tools Method R Trace 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 Method R Workbench TRASIR SimDiff Cary Millsap
  3. 3. @CaryMillsap The Case for Homemade Logging 3
  4. 4. 1988 BMW 325 4@CaryMillsap
  5. 5. @CaryMillsap OBDII 5
  6. 6. 6@CaryMillsap A short story.
  7. 7. Hey, the TPS report is slow. It always used to run in about 10 minutes, but then it went to 20, and now it’s taking over an hour. Any idea why? 🤣 🤣 🤣 What kind of idea would I have? It’s *your* code, bruh. 7@CaryMillsap
  8. 8. So, you stick some print statements into your code. You recompile it. You test it. You commit it and push it. You deploy it. 8@CaryMillsap
  9. 9. Still slow. Here, I’ve pushed a new executable. Try it now. When it’s finished, email me the file called $HOME/tps.log Ok, check your mail. Yeah, I know. But the log file will tell me where it’s spending its time. Just curious. Why didn’t it do the thing with the log file to begin with? ●●● 9@CaryMillsap
  10. 10. @CaryMillsap Homemade logging What would those printf() statements look like? function f(stuff) { printf(LOG, "%s %s %sn", timestamp, "f{", stuff); for record in (records) { process(record); } printf(LOG, "%s %s %d recordsn", timestamp, "}", count(records)); } Then you’ll need to parse the log to compute durations. (Or change the code to print them.) 10
  11. 11. @CaryMillsap Homemade logging What would those printf() statements look like? function f(stuff) { printf(LOG, "%s %s %sn", timestamp, "f{", stuff); for record in (records) { process(record); } printf(LOG, "%s %s %d recordsn", timestamp, "}", count(records)); } Maybe you’ll need more printf calls to cope with skew in iteration durations. 11
  12. 12. @CaryMillsap 1. package com.test; 2.   3. import org.apache.logging.log4j.Logger; 4. import org.apache.logging.log4j.LogManager; 5.   6. import java.util.Random; 7.   8. public class TestService { 9. private Logger logger = LogManager.getLogger(TestService.class.getName()); 10.   11. private String[] messages = new String[] { 12. "Hello, World", 13. "Goodbye Cruel World", 14. "You had me at hello" 15. }; 16. private Random rand = new Random(1); 17.   18. public void setMessages(String[] messages) { 19. logger.traceEntry(new JsonMessage(messages)); 20. this.messages = messages; 21. logger.traceExit(); 22. } 23.   24. public String[] getMessages() { 25. logger.traceEntry(); 26. return logger.traceExit(messages, new JsonMessage(messages)); 27. } 28.   29. public String retrieveMessage() { 30. logger.entry(); 31.   32. String testMsg = getMessage(getKey()); 33.   34. return logger.exit(testMsg); 35. } 36.   37. public void exampleException() { 38. logger.entry(); 39. try { 40. String msg = messages[messages.length]; 41. logger.error("An exception should have been thrown"); 42. } catch (Exception ex) { 43. logger.catching(ex); 44. } 45. logger.exit(); 46. } 47.   48. public String getMessage(int key) { 49. logger.entry(key); 50.   51. String value = messages[key]; 52.   53. return logger.exit(value); 54. } 55.   56. private int getKey() { 57. logger.entry(); 58. int key = rand.nextInt(messages.length); 59. return logger.exit(key); 60. } 61. } Homemade logging What would those printf() statements look like? function f(stuff) { printf(LOG, "%s %s %sn", timestamp, "f{", stuff); for record in (records) { process(record); } printf(LOG, "%s %s %d recordsn", timestamp, "}", count(records)); } Maybe you’ll use Log4j. 12
  13. 13. @CaryMillsap Homemade logging What would those printf() statements look like? function f(stuff) { printf(LOG, "%s %s %sn", timestamp, "f{", stuff); for record in (records) { process(record); } printf(LOG, "%s %s %d recordsn", timestamp, "}", count(records)); } Maybe you’ll create a --debug option to control it. 13
  14. 14. @CaryMillsap This function: 23.8% debug function check_for_updates($product, $platform, $version, $debug=0) { // Find update candidate filenames in distro directory. $zero_distroversion = "0.0.0.0"; // -INF value for initialization. $distro_dir = distribution_filename(); if ($dir = opendir($distro_dir)) { $greatest_distroversion = $zero_distroversion; if ($debug) echo "<p>Searching files in '$distro_dir':</p>"; if ($debug) echo "<ul>"; while (false !== ($entry = readdir($dir))) { // http://php.net/manual/en/function.readdir.php if ($entry === "." or $entry === "..") { continue; } if ($debug) echo "<li>"; if ($debug) echo $entry; if (preg_match("/^$product-([0-9.]+)-$platform./", $entry, $match)) { // Assumption: filename structure. $distroversion = $match[1]; if ($debug) echo " is a distro match"; if (version_compare($distroversion, $version, ">")) { if ($debug) echo ", and an update candidate because $distroversion > $version"; if (version_compare($distroversion, $greatest_distroversion, ">")) { if ($debug) echo ", and the best so far because $distroversion > $greatest_distroversion"; $greatest_distroversion = $distroversion; $update_filename = $entry; } else { if ($debug) echo ", but not the best because $distroversion ≯ $greatest_distroversion"; } 14
  15. 15. @CaryMillsap Why would I do that? 15 Coz my world is the opposite of this world. I have to operate the software I write. ☞
  16. 16. @CaryMillsap We find stepping through a program [with a debugger] less productive than thinking harder and adding output statements and self- checking code at critical places. …More important, debugging statements stay with the program; debugging sessions are transient. —Brian Kernighan and Rob Pike The Practice of Programming 16
  17. 17. @CaryMillsap Oracle Extended SQL Trace 17
  18. 18. @CaryMillsap What you get with sql_trace Database calls (dbcalls) System calls (syscalls) Values bound to placeholders (“bind variables”) Query plan (row source) operations 18
  19. 19. @CaryMillsap sql_trace shows control flow $ vim PSP_ora_4620_00007.trc 19
  20. 20. @CaryMillsap 20 Tools make it easier to read
  21. 21. @CaryMillsap Innovative Specifications 21
  22. 22. Edit Email Assign Resolve Active Priority 3 – Required Edit Email Assign Resolve Opened by Cary Millsap 05/24/2018 (Today) 11:34 AM Cary Millsap Project: TPS Area: logging Milestone: 1.1.0 Kanban Column 1.1.0.1 @CaryMillsap 22 10001 An operator (e.g., a DBA) must be able to control tracing of selected business tasks with Oracle’s dbms_monitor PL/SQL package. For example, we should be able to trace: - the next OE job - the next OE BOOK job - the next job executed by nwells Operator-controlled tracing of task executions
  23. 23. @CaryMillsap Trace all OE executionsPL/SQL dbms_monitor.serv_mod_act_trace_enable( service_name => 'SYS$USERS', module_name => 'OE', action_name => dbms_monitor.all_actions, waits => true, binds => false, plan_stat => 'FIRST_EXECUTION' ); But this works only if your code sets its module name. 23
  24. 24. @CaryMillsap Trace all OE BOOK executionsPL/SQL dbms_monitor.serv_mod_act_trace_enable( service_name => 'SYS$USERS', module_name => 'OE', action_name => 'BOOK', waits => true, binds => false, plan_stat => 'FIRST_EXECUTION' ); This works only if your code sets its module and action names. 24
  25. 25. @CaryMillsap Trace all nwells executionsPL/SQL dbms_monitor.client_id_trace_enable( client_id => 'nwells', waits => true, binds => false, plan_stat => 'FIRST_EXECUTION' ); This works only if your code sets its client ID. 25
  26. 26. @CaryMillsap User session handle attributes Settable and gettable with OCI, JDBC, etc. Visible in v$session service_name
 module
 action
 client_identifier Values can change during a session Identify sessions or parts of sessions 26 OE/BOOK OE/PICK OE/SHIP Oracle session connect disconnect set_module('OE', 'BOOK') set_module(null, null) set_module(null, null) set_module(null, null) set_module('OE', 'PICK') set_module('OE', 'SHIP') time
  27. 27. @CaryMillsap Marking your codePL/SQL dbms_session.set_identifier(sys_context('userenv', 'enterprise_identity')); dbms_application_info.set_module('OE', 'BOOK'); -- Your OE BOOK code dbms_session.set_identifier(null); dbms_application_info.set_module(null, null); 27
  28. 28. @CaryMillsap Marking your codeJDBC 12c Properties p = new Properties(); p.put("OCSID.MODULE", "OE"); p.put("OCSID.ACTION", "BOOK"); p.put("OCSID.CLIENTID", getUserName()); connection.setClientInfo(p); /* Your OE BOOK code */ p.put("OCSID.MODULE", ""); p.put("OCSID.ACTION", ""); p.put("OCSID.CLIENTID", ""); connection.setClientInfo(p); 28
  29. 29. @CaryMillsap Better factoringJDBC 12c connection.begin_task("OE BOOK"); /* Your OE BOOK code */ connection.end_task(); 29
  30. 30. @CaryMillsap The new codepseudocode sub begin_task(t) { (mod, act) = split(/ /, t, 2); setClientInfo(properties(mod, act, getUserName())); } sub end_task() { setClientInfo(properties("", "", "")); } 30
  31. 31. Edit Email Assign Resolve Active Priority 3 – Required Edit Email Assign Resolve Opened by Cary Millsap 05/24/2018 (Today) 11:34 AM Cary Millsap Project: TPS Area: logging Milestone: 1.1.0 Kanban Column 1.1.0.1 @CaryMillsap 31 10002 Our connection pooling application makes it difficult to isolate individual user experiences in the trace data. The Method R Workbench trick of identifying oceans, islands, and rivers with mrskew --thinktime=z is a start, but we want to perfectly isolate experiences. We can do this by printing a unique experience ID (a UUID) to the trace file at the beginning of a task’s execution, and then printing an empty experience ID at the end. This will give tools like mrskew a group-by handle that maps perfectly to the user experience. Write experience ID to the trace file
  32. 32. @CaryMillsap List of experience durations $ mrskew *.trc --group='sprintf("%-8s %-36s %s", $client_id, $experience_id, $file)' … CLIENT-ID EXPERIENCE-ID FILE DURATION % CALLS MEAN MIN MAX ----------------------------------------------------------------- ------------ ------ --------- -------- -------- -------- nwells c6a1c359-5766-4263-9e3e-8e600bb7dba9 gxl_ora_131168.trc 9.447247 0.5% 8 1.180906 0.000000 8.075276 cshaftig 822a94c6-d27a-4804-84fe-5a7fed03ed9f gxl_ora_110636.trc 7.560207 0.4% 9 0.840023 0.000000 7.543424 nwells 733f8c60-2bd3-4fdd-a638-d304f75b1aef gxl_ora_91144.trc 7.525153 0.4% 15 0.501677 0.000000 7.489669 rmorbisun afcab6e4-02e8-47ed-a3f8-ca394ddd17cb gxl_ora_56988.trc 6.342819 0.3% 16 0.396426 0.000000 5.449377 krajita 64e57451-bf65-4022-a927-0cf2567c2fe1 gxl_ora_61704.trc 5.521687 0.3% 7 0.788812 0.000000 5.505351 89,074 others 1,975.121691 98.2% 1,233,058 0.001602 0.000000 4.900948 ----------------------------------------------------------------- ------------ ------ --------- -------- -------- -------- TOTAL (89,079) 2,011.518804 100.0% 1,233,113 0.001631 0.000000 8.075276 32
  33. 33. @CaryMillsap List of experience durations $ mrskew *.trc --group='sprintf("%-8s %-36s %s", $client_id, $experience_id, $file)' … CLIENT-ID EXPERIENCE-ID FILE DURATION % CALLS MEAN MIN MAX ----------------------------------------------------------------- ------------ ------ --------- -------- -------- -------- nwells c6a1c359-5766-4263-9e3e-8e600bb7dba9 gxl_ora_131168.trc 9.447247 0.5% 8 1.180906 0.000000 8.075276 cshaftig 822a94c6-d27a-4804-84fe-5a7fed03ed9f gxl_ora_110636.trc 7.560207 0.4% 9 0.840023 0.000000 7.543424 nwells 733f8c60-2bd3-4fdd-a638-d304f75b1aef gxl_ora_91144.trc 7.525153 0.4% 15 0.501677 0.000000 7.489669 rmorbisun afcab6e4-02e8-47ed-a3f8-ca394ddd17cb gxl_ora_56988.trc 6.342819 0.3% 16 0.396426 0.000000 5.449377 krajita 64e57451-bf65-4022-a927-0cf2567c2fe1 gxl_ora_61704.trc 5.521687 0.3% 7 0.788812 0.000000 5.505351 89,074 others 1,975.121691 98.2% 1,233,058 0.001602 0.000000 4.900948 ----------------------------------------------------------------- ------------ ------ --------- -------- -------- -------- TOTAL (89,079) 2,011.518804 100.0% 1,233,113 0.001631 0.000000 8.075276 33
  34. 34. @CaryMillsap Drill into an experience $ mrskew gxl_ora_131168.trc --where='$experience_id eq "c6a1c359-5766-4263-9e3e-8e600bb7dba9"' CALL-NAME DURATION % CALLS MEAN MIN MAX ----------------------------- -------- ------ ----- -------- -------- -------- enq: TX - row lock contention 8.075276 85.5% 1 8.075276 8.075276 8.075276 log file sync 1.355818 14.4% 1 1.355818 1.355818 1.355818 EXEC 0.015600 0.2% 1 0.015600 0.015600 0.015600 SQL*Net message from client 0.000548 0.0% 1 0.000548 0.000548 0.000548 SQL*Net message to client 0.000005 0.0% 2 0.000002 0.000002 0.000003 2 others 0.000000 0.0% 2 0.000000 0.000000 0.000000 ----------------------------- -------- ------ ----- -------- -------- -------- TOTAL (7) 9.447247 100.0% 8 1.180906 0.000000 8.075276 34
  35. 35. @CaryMillsap Oceans, Islands, and Rivers 35
  36. 36. @CaryMillsap 36 WAIT … nam='SQL*Net message from client' ela= 1202689 … stuff for Experience A WAIT … nam='SQL*Net message from client' ela= 4260917 … stuff for Experience B WAIT … nam='SQL*Net message from client' ela= 5213365 … stuff for Experience C WAIT … nam='SQL*Net message from client' ela= 2044420 …
  37. 37. 37@CaryMillsap Such trace files have islands of activity in an ocean of idleness.
  38. 38. 38@CaryMillsap But…
  39. 39. 39@CaryMillsap An island can have rivers.
  40. 40. 40@CaryMillsap So can a trace file.
  41. 41. 41@CaryMillsap WAIT … nam='SQL*Net message from client' ela= 1202689 … *** CLIENT ID:(nwells) *** EXPERIENCE ID:(c6a1c359-5766-4263-9e3e-8e600bb7dba9) stuff for Experience A WAIT … nam='SQL*Net message from client' ela= 342 more stuff for Experience A WAIT … nam='SQL*Net message from client' ela= 1492 yet more stuff for Experience A … WAIT … nam='SQL*Net message from client' ela= 4260917 … *** CLIENT ID:(cshaftig) *** EXPERIENCE ID:(822a94c6-d27a-4804-84fe-5a7fed03ed9f) stuff for Experience B WAIT … nam='SQL*Net message from client' ela= 2928 more stuff for Experience B … WAIT … nam='SQL*Net message from client' ela= 5213365 … *** CLIENT ID:(nwells) *** EXPERIENCE ID:(733f8c60-2bd3-4fdd-a638-d304f75b1aef) stuff for Experience C WAIT … nam='SQL*Net message from client' ela= 855 more stuff for Experience C … WAIT … nam='SQL*Net message from client' ela= 2044420 …
  42. 42. 42@CaryMillsap WAIT … nam='SQL*Net message from client' ela= 1202689 … *** CLIENT ID:(nwells) *** EXPERIENCE ID:(c6a1c359-5766-4263-9e3e-8e600bb7dba9) stuff for Experience A WAIT … nam='SQL*Net message from client' ela= 342 more stuff for Experience A WAIT … nam='SQL*Net message from client' ela= 1492 yet more stuff for Experience A … WAIT … nam='SQL*Net message from client' ela= 4260917 … *** CLIENT ID:(cshaftig) *** EXPERIENCE ID:(822a94c6-d27a-4804-84fe-5a7fed03ed9f) stuff for Experience B WAIT … nam='SQL*Net message from client' ela= 2928 more stuff for Experience B … WAIT … nam='SQL*Net message from client' ela= 5213365 … *** CLIENT ID:(nwells) *** EXPERIENCE ID:(733f8c60-2bd3-4fdd-a638-d304f75b1aef) stuff for Experience C WAIT … nam='SQL*Net message from client' ela= 855 more stuff for Experience C … WAIT … nam='SQL*Net message from client' ela= 2044420 …
  43. 43. @CaryMillsap The new codepseudocode sub begin_task(t) { (mod, act) = split(/ /, t, 2); setClientInfo(properties(mod, act, getUserName()); xid = uuid(); push(xid_stack, (xid, t)); dbms_log.ksdwrt(1, sprintf("EXPERIENCE ID:(%s)", xid)); } sub end_task() { setClientInfo(properties("", "", "")); pop(xid_stack); dbms_log.ksdwrt(1, "EXPERIENCE ID:()"); } 43
  44. 44. Edit Email Assign Resolve Active Priority 3 – Required Edit Email Assign Resolve Opened by Cary Millsap 05/24/2018 (Today) 11:34 AM Cary Millsap Project: TPS Area: logging Milestone: 1.1.0 Kanban Column 1.1.0.1 @CaryMillsap 44 10003 We’ve had intermittent performance problems with OE BOOK. We don’t want to trace OE BOOK every time it runs, but it would be nice if we could trace it for some percentage of executions. We want to control that percentage from a table that we can modify through a simple APEX application. Trace only some executions of a given program
  45. 45. @CaryMillsap Trace every execution
 pseudocode dbms_session.session_trace_enable(true, false, 'FIRST_EXECUTION'); -- Your OE BOOK code dbms_session.session_trace_disable(); 45
  46. 46. @CaryMillsap Trace only some executions
 pseudocode if (should_trace('OE BOOK') { dbms_session.session_trace_enable(true, false, 'FIRST_EXECUTION'); } -- Your OE BOOK code dbms_session.session_trace_disable(); 46
  47. 47. @CaryMillsap Trace only some executions
 pseudocode if (should_trace('OE BOOK')) { dbms_session.session_trace_enable(true, false, 'FIRST_EXECUTION'); } -- Your OE BOOK code dbms_session.session_trace_disable(); sub should_trace(t) {
 select proportion from trace_control where task = :t; return (dbms_random.value(0,1) < proportion);
 } 47 task_name proportion OE BOOK 0.05 OE PICK 0.02 … … trace_control
  48. 48. @CaryMillsap Trace only some executions
 pseudocode sub should_trace(t) {
 select proportion from trace_control where task = :t; return (dbms_random.value(0,1) < proportion);
 } task_name proportion OE BOOK 0.05 OE PICK 0.02 … … trace_control 48 p = 0.95 should_trace('OE BOOK') == false p = 0.05 should_trace('OE BOOK') == true 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
  49. 49. @CaryMillsap The new code
 pseudocode sub begin_task(t) { (mod, act) = split(/ /, t, 2); setClientInfo(properties(mod, act, getUserName()); xid = uuid(); push(xid_stack, (xid, t)); dbms_log.ksdwrt(1, sprintf("EXPERIENCE ID:(%s)", xid)); if (should_trace(t)) { session_trace_enable(true, true, 'first_execution'); } } sub end_task() { setClientInfo(properties("", "", "")); pop(xid_stack); dbms_log.ksdwrt(1, "EXPERIENCE ID:()"); session_trace_disable(); } 49
  50. 50. Edit Email Assign Resolve Active Priority 3 – Required Edit Email Assign Resolve Opened by Cary Millsap 05/24/2018 (Today) 11:34 AM Cary Millsap Project: TPS Area: logging Milestone: 1.1.0 Kanban Column 1.1.0.1 @CaryMillsap 50 10003 We don't always want to use bind=true and plan_stat='first_execution'. We want to control those from trace_control as well. Manage tracing levels from trace_control
  51. 51. @CaryMillsap Measurement intrusion Enough detail, but not too much. Oracle uses events and levels. $ORACLE_HOME/rdbms/mesg/oraus.msg • 10046 “enable SQL statement timing” levels 1, 4, 8, 16, 32, 64, … (sql_trace) • 10053 “CBO Enable optimizer trace” • 10200 “consistent read buffer status” 51
  52. 52. @CaryMillsap How we avoid 10046 MIE 1. sql_trace wait=true, bind=false, plan_stat=first_execution 2. If application has lightweight row-by-row executions, we fix it. 3. sql_trace wait=true, bind=true, plan_stat=all_executions 52
  53. 53. @CaryMillsap The new codepseudocode sub begin_task(t) { (mod, act) = split(/ /, t, 2); setClientInfo(properties(mod, act, getUserName()); xid = uuid(); push(xid_stack, (xid, t)); dbms_log.ksdwrt(1, sprintf("EXPERIENCE ID:(%s)", xid)); if ((bind, stat) = should_trace(t)) { session_trace_enable(true, bind, stat); } } sub end_task() { setClientInfo(properties("", "", "")); pop(xid_stack); dbms_log.ksdwrt(1, "EXPERIENCE ID:()"); session_trace_disable(); } 53 task_name proportion bind stat OE BOOK 0.05 FALSE FIRST_EXECUTION OE PICK 0.02 TRUE ALL_EXECUTIONS … … … … trace_control
  54. 54. Edit Email Assign Resolve Active Priority 3 – Required Edit Email Assign Resolve Opened by Cary Millsap 05/24/2018 (Today) 11:34 AM Cary Millsap Project: TPS Area: logging Milestone: 1.1.0 Kanban Column 1.1.0.1 @CaryMillsap 54 10004 When a user has a performance problem with the application, she should be able to click Help › Debug › Trace, which will inspire a properly time-scoped trace of the next business task she executes. User controls tracing with Help › Debug › Trace
  55. 55. @CaryMillsap Help › Debug › Trace How it usually works: 1. User clicks Help › Debug › Trace. 2. This triggers immediate session trace enable. 3. User eventually executes her task. 4. Clicks Help › Debug › Stop Trace. Not what you want. 55
  56. 56. @CaryMillsap It’s not the trace file you want You need: trace enable == task begin trace disable == task end Otherwise, you get either too much data,
 or not enough. 56 trace disable task end task begin trace enable trace file you got trace file you want time
  57. 57. @CaryMillsap Help › Debug › Trace A user turns on tracing. vs. A user expresses the intention to trace the next task execution. Help › Debug › Trace should set a boolean. begin_task queries the boolean. 57
  58. 58. @CaryMillsap The new codepseudocode sub begin_task(t) { (mod, act) = split(/ /, t, 2); setClientInfo(properties(mod, act, getUserName()); xid = uuid(); push(xid_stack, (xid, t)); dbms_log.ksdwrt(1, sprintf("EXPERIENCE ID:(%s)", xid)); if (isTraceIntended() or (bind, stat) = should_trace(t)) { session_trace_enable(true, bind, stat); } } sub end_task() { setClientInfo(properties("", "", "")); pop(xid_stack); dbms_log.ksdwrt(1, "EXPERIENCE ID:()"); session_trace_disable(); } 58
  59. 59. @CaryMillsap Wrap-up 59
  60. 60. @CaryMillsap More specs (discussion) • Trace the first OE BOOK execution every hour. • Trace p% of Larry’s executions, but q% of Nancy’s. • Trace p% of executions whose durations have one of the top ten variance-to- mean ratios (VMR) in your application. • Trace only if the job is less than p% complete after running for m minutes. Could you do these even if you don’t have source code access? How? 60
  61. 61. @CaryMillsap Hundreds of specs you could meet Trace when you need. Persist every response time. Predict response time problems. Track pathway through the application. Write harvesters, uploaders, profilers for the data. Log to shared memory segments for ultra-high throughput. You can build anything you want; application self-measurement is no big deal. 61
  62. 62. @CaryMillsap For more information… 62 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 Available at
  63. 63. @CaryMillsap 63 Method R TM www.cintra.com method-r.com

×