That’s not the 23rd article I’ve written on sql_trace, it’s just that there’s a little “catch-up” detail about sql_trace that I recently discovered in 23.2 (though it might also be working in 21c or even in recent versions of 19c).
Although level 4 and 8 (binds and waits) of the SQL trace event are commonly known, and the more modern style of calls to sql_trace with the added plan_stat options are fairly well known it’s only in 23c (possibly 21c) that all the plan_stat options get implemented in dbms_session and dbms_monitor. From some time back in the 11g timeline we’ve been able to execute calls like:
alter system set events '
sql_trace[SQL:9tz4qu4rj9rdp]
bind=false,
wait=true,
plan_stat=all_executions
'
;
Taking advantage of the “oradebug doc” command (which can only be run by a highly privileged user), you could discover the available options for the plan_stat:
SQL> oradebug doc event name sql_trace
sql_trace: event for sql trace
Usage
-------
sql_trace
wait < false | true >,
bind < false | true >,
plan_stat < never | first_execution | all_executions | adaptive >,
level <ub4>
The default value for plan_stat is first_execution which is usually adequate, but if you were trying to find out why a particular query sometimes runs very slowly compared to usual you might want to set it to all_executions. If the query executes extremely frequently, though, and produces a fairly length execution plan you might decide to set the value to adaptive (see end notes) which ought to limit the frequency with which the execution plan is dumped into the trace file.
Note: the threat of very long plans for very quick executions of an extremely popular statement comes from two directions – the extra “execution” time to get the plan written to the trace file, and the total size of all the files dumped to the trace directory. Depending on your requirements you might be able to use the “UTS trace” setup to limit the volume kept on disc.
If you check the packages dbms_session and dbms_monitor you will find the following procedures:
QL> desc dbms_session
...
PROCEDURE SESSION_TRACE_ENABLE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
WAITS BOOLEAN IN DEFAULT
BINDS BOOLEAN IN DEFAULT
PLAN_STAT VARCHAR2 IN DEFAULT
...
SQL> desc dbms_monitor
...
PROCEDURE CLIENT_ID_TRACE_ENABLE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
CLIENT_ID VARCHAR2 IN
WAITS BOOLEAN IN DEFAULT
BINDS BOOLEAN IN DEFAULT
PLAN_STAT VARCHAR2 IN DEFAULT
PROCEDURE DATABASE_TRACE_ENABLE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
WAITS BOOLEAN IN DEFAULT
BINDS BOOLEAN IN DEFAULT
INSTANCE_NAME VARCHAR2 IN DEFAULT
PLAN_STAT VARCHAR2 IN DEFAULT
PROCEDURE SERV_MOD_ACT_TRACE_ENABLE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
SERVICE_NAME VARCHAR2 IN
MODULE_NAME VARCHAR2 IN DEFAULT
ACTION_NAME VARCHAR2 IN DEFAULT
WAITS BOOLEAN IN DEFAULT
BINDS BOOLEAN IN DEFAULT
INSTANCE_NAME VARCHAR2 IN DEFAULT
PLAN_STAT VARCHAR2 IN DEFAULT
PROCEDURE SESSION_TRACE_ENABLE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
SESSION_ID BINARY_INTEGER IN DEFAULT
SERIAL_NUM BINARY_INTEGER IN DEFAULT
WAITS BOOLEAN IN DEFAULT
BINDS BOOLEAN IN DEFAULT
PLAN_STAT VARCHAR2 IN DEFAULT
...
Chris Antognini wrote an article some years ago listing the “10046 trace” levels and the relationships between the available numeric levels and the named parameter format (adaptive = 64). In the note he pointed out that adaptive was not available as a plan_stat value in dbms_session and dbms_monitor, and that Enhancement Request #14499199 had been raised to correct this omission. Since then I’ve run a little script from time to time to check if the ER has been fulfilled:
olumn sid new_value my_sid
column serial# new_value my_serial
select sid, serial#
from v$session ses
where ses.sid = (
select ms.sid
from v$mystat ms
where rownum = 1
)
;
execute dbms_monitor.session_trace_enable( &my_sid, &my_serial, waits=>false, binds=>false, plan_stat=>'adaptive')
execute dbms_session.session_trace_enable(waits=>false, binds=>false, plan_stat=>'adaptive');
execute dbms_monitor.session_trace_disable( &my_sid, &my_serial)
execute dbms_session.session_trace_disable;
This depends on the user having suitable privileges on the packages and on a couple of dynamic performance views, and all that happens is that it succeeds (or fails) to enable tracing. Here’s the output from 19.11.0.0 of the two calls to enable:
BEGIN dbms_monitor.session_trace_enable( 40, 56799, waits=>false, binds=>false, plan_stat=>'adaptive'); END;
*
ERROR at line 1:
ORA-30449: syntax error in parameter
ORA-06512: at "SYS.DBMS_MONITOR", line 123
ORA-06512: at line 1
BEGIN dbms_session.session_trace_enable(waits=>false, binds=>false, plan_stat=>'adaptive'); END;
*
ERROR at line 1:
ORA-30449: syntax error in parameter
ORA-06512: at "SYS.DBMS_SESSION", line 343
ORA-06512: at line 1
Then on the upgrade to 23.2.0.0, the boring but satisfying:
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
Readers with versions in the gap between 19.11.0.0 and 23.2.0.0 are invited to run a check and report the results in the comments to narrow down when the enhancement became available. [Update: see comments #1 and #2 – versions up to 19.21 show the same error; and comment #5 shows the same error in 21.3]
plan_stat=adaptive
There are a couple of notes on MOS about the meaning/effect of this setting. They’re not 100% consistent with each other.
Doc ID 21154.1 says:
This dumps the STAT information if a SQL took more than about 1 minute thereby giving information for the more expensive SQLs and for different executions of such SQLs.
Doc ID 8328200 (relating to Bug 8328200) says:
“adaptive” mode dumps STAT lines in SQL trace for every minute of dbtime per shared cursor.
As you can see you can read the two statements as trying to say the same thing, but there is some ambiguity in both statements, and some need for clarification of terms. So I’ve done a couple of simple experiments – basically running a PL/SQL loop that executes the same statement 120 times, where each execution takes a little less 3 seconds to complete.
Cutting the top and tail from each trace file left me with 120 “FETCH” lines; a few of these lines were immediately followed by STAT lines, most were followed by CLOSE lines with no STAT lines reported for the execution. Here are the first few lines of the results from a trace file generated by 23.2 from a call to: “grep -A+1 FETCH {tracefile}”:
FETCH #140175454862744:c=2737978,e=2814244,p=0,cr=277822,cu=0,mis=0,r=1,dep=1,og=1,plh=3153623734,tim=36476287935
STAT #140175454862744 id=1 cnt=1 pid=0 pos=1 obj=0 op='SORT AGGREGATE (cr=277822 pr=0 pw=0 str=1 time=2814245 dr=0 dw=0 us)'
--
FETCH #140175454862744:c=2758633,e=2885235,p=0,cr=277822,cu=0,mis=0,r=1,dep=1,og=1,plh=3153623734,tim=36479173822
CLOSE #140175454862744:c=2,e=1,dep=1,type=3,tim=36479173972
--
Piping this into “grep -B+1 STAT” extracted just the FETCH/STAT pairs, which I could then pass through “grep FETCH” to get the output that I wanted to see: the “tim=” values for only those FETCH calls that were followed by STAT lines:
grep -A+1 FETCH {tracefile} | grep -B+1 STAT | grep FETCH
FETCH #140175454862744:c=2737978,e=2814244,p=0,cr=277822,cu=0,mis=0,r=1,dep=1,og=1,plh=3153623734,tim=36476287935
FETCH #140175454862744:c=2716296,e=2782323,p=0,cr=277822,cu=0,mis=0,r=1,dep=1,og=1,plh=3153623734,tim=36541290925
FETCH #140175454862744:c=2804165,e=2916326,p=0,cr=277822,cu=0,mis=0,r=1,dep=1,og=1,plh=3153623734,tim=36610338064
FETCH #140175454862744:c=2677000,e=2737197,p=0,cr=277822,cu=0,mis=0,r=1,dep=1,og=1,plh=3153623734,tim=36676533249
FETCH #140175454862744:c=2722436,e=2796966,p=0,cr=277822,cu=0,mis=0,r=1,dep=1,og=1,plh=3153623734,tim=36744048403
FETCH #140175454862744:c=2725066,e=2792661,p=0,cr=277822,cu=0,mis=0,r=1,dep=1,og=1,plh=3153623734,tim=36811536449
If you do the arithmetic with the tim= values you’ll find that the time between the executions that reported their execution plan in STAT lines varies from about 65 seconds to 69 seconds. The results from 19.11 were similar, varying from 64.9 seconds to 67.9 seconds. So the dumping STAT lines is dependent on spending (approximately) one minute of dbtime in execution (as both MOS Documents indicate) but it’s once every minute, and it’s time that can be accumulated over many executions of the statement. Part of the deviation from one minute comes, of course, from the fact the STAT lines are dumped only as the cursor closes.
The other detail that needs investigation is the interpretation of the clause “per shared cursor”. If I ran my test from two separate sessions concurrently would I be accumulating “db minutes” twice as fast and dumping STAT lines twice as frequently? The answer was yes – providing the two sessions acquired the same child cursor in v$sql.
To demonstrate this, I ran two concurrent copies of the PL/SQL loop, starting one session about 65 seconds after the other. My first trace file showed its second set of STAT lines after about 63 seconds then roughly every 33 seconds, and the second trace file (starting about one minute late) showed its second set of STAT lines after about 33 seconds, repeating that interval between dumps until nearly the end of its run when the last gap (after the first session had finished) stretched to 50 seconds.
Is it good enough?
Maybe, maybe not. It gives you a sample of execution plans for queries that accumulate “a lot” of time while using a particular child cursor, and that might be sufficient for some purposes.
If you have a frequently executed query that usually takes a couple of seconds but occasionally takes 90 seconds then that 90 second execution will show up in the trace file, either because it’s a different plan, and gets dumped on the first execution, or because it will have increased the shared execution time by more than 60 seconds.
If you have a query that executes extremely frequently and takes a couple of hundredths of a second each time but occasionally takes 5 seconds the adaptive option may not help. As with the 90 second/change of plan case you’ll see the plan; but all it does if the plan doesn’t change is improve your chances of seeing the stats of that slow execution plan – it has to take place in that little window where its execution time just tips the running total over the next 60 second limit.
Hi Jonathan,
thanks for this insights on the plan_stat option.
I checked versions 19.19, 19.20 and 19.21. For all of them I get “ORA-30449: syntax error in parameter” when I run your test case with dbms_monitor.session_trace_enable.
Cheers,
Mathias
Comment by Mathias Zarick — October 27, 2023 @ 1:18 pm BST Oct 27,2023 |
Version 19.20.0.0.0 ( from v$version )
BEGIN dbms_monitor.session_trace_enable( 40, 56799, waits=>false, binds=>false, plan_stat=>’adaptive’); END;
*
ERROR at line 1:
ORA-30449: syntax error in parameter
ORA-06512: at “SYS.DBMS_MONITOR”, line 123
ORA-06512: at line 1
BEGIN dbms_session.session_trace_enable(waits=>false, binds=>false, plan_stat=>’adaptive’); END;
*
ERROR at line 1:
ORA-30449: syntax error in parameter
ORA-06512: at “SYS.DBMS_SESSION”, line 343
ORA-06512: at line 1
Comment by Anonymous — October 27, 2023 @ 1:21 pm BST Oct 27,2023 |
ah, Mathias posted same time I did, he won the race :-)
Comment by Anonymous — October 27, 2023 @ 1:22 pm BST Oct 27,2023 |
Mathias and Anonymous (I don’t know why most comments are current showing Anonymous),
Thanks for running the tests on newer versions. I’ve added a note in the text.
Regards
Jonathan Lewis
Comment by Jonathan Lewis — October 27, 2023 @ 1:33 pm BST Oct 27,2023 |
Hello Jonathan,
For 21c,
v$version.banner_full = Oracle Database 21c Express Edition Release 21.0.0.0.0 – Production Version 21.3.0.0.0
I still get
ORA-30449: syntax error in parameter
ORA-06512: at “SYS.DBMS_SESSION”, line 343
ORA-06512: at line 1
for DBMS_SESSION .
I have no privileges for DBMS_MONITOR, but I guess it is probably the same.
Best Regards,
Iudith Mentzel
Comment by Anonymous — October 27, 2023 @ 10:00 pm BST Oct 27,2023 |
Iudith,
Thanks for running the test and reporting back.
Regards
Jonathan Lewis
Comment by Jonathan Lewis — October 27, 2023 @ 10:57 pm BST Oct 27,2023 |
[…] SQL_trace 23 […]
Pingback by Troubleshooting catalogue | Oracle Scratchpad — October 31, 2023 @ 3:47 pm GMT Oct 31,2023 |